0

So I'm trying to create a Winsock UDP server out of a TCP server, but I just can't seem to get it to work. The official winsock documentation doesn't seem to cover UDP servers (atleast as far as I could find).

The working TCP server is here:

#include <iostream>
#include <ws2tcpip.h>
#include <windows.h>

using namespace std;

int main()
{
    const char* port = "888";
    char message[50] = {0};

// Initialize WINSOCK
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2,2), &wsaData);

// Create the listening socket
    SOCKET ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    SOCKET DataSocket;

// Initialize the sample struct and get another filled struct of the same type and old values
    addrinfo hints, *result(0); ZeroMemory(&hints, sizeof(hints));
    hints.ai_family   = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags    = AI_PASSIVE;

    getaddrinfo(0, port, &hints, &result);

// Bind the socket to the ip and port provided by the getaddrinfo and set the listen socket's type to listen
    bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
    listen(ListenSocket, SOMAXCONN); // Only sets the type to listen ( doesn't actually listen )

// Free unused memory
    freeaddrinfo(result);

// Accept a connection
    DataSocket = accept(ListenSocket, 0, 0);
    cout << "Connected!" << endl << endl;

// Recieve data
    while(true){
        recv(DataSocket, message, 10, 0);
        cout << "Recieved: \n\t" << message << endl << endl;
        system("cls");
        Sleep(10);
    }

// Shutdown
    shutdown(DataSocket, SD_BOTH);
    shutdown(ListenSocket, SD_BOTH);
    WSACleanup();
    exit(0);
    return 0;
}

How could I convert it to a working UDP server? In my experience just changing the protocol and socktype doesn't cut it.

Code update:

const char* port = "888";
char message[50] = {0};

// Initialize WINSOCK
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);

// Create the listening socket
SOCKET DataSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 

// Initialize the sample struct and get another filled struct of the same type and old values
addrinfo hints, *result(0); ZeroMemory(&hints, sizeof(hints));
hints.ai_family   = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags    = AI_PASSIVE;

getaddrinfo(0, port, &hints, &result);

// Bind the socket to the ip and port provided by the getaddrinfo and set the listen socket's type to listen
bind(DataSocket, result->ai_addr, (int)result->ai_addrlen);
listen(DataSocket, SOMAXCONN); // Only sets the type to listen ( doesn't actually listen )

// Free unused memory
freeaddrinfo(result);

// Recieve data
while(true){
    int bytes = recvfrom(DataSocket, message, 20, 0, 0, 0);
}
Rokas Višinskas
  • 533
  • 4
  • 12

1 Answers1

2

To convert a TCP server into a UDP server at least the following changes must be done:

  1. Replace SOCK_STREAM with SOCK_DGRAM; IPPROTO_TCP with IPPROTO_UDP.
  2. Remove listen and accept calls.
  3. Replace recv with recvfrom.
  4. Replace send with sendto.
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • 1
    I would bold *at least*. These are changes to get code work, not server :) – Afshin Oct 31 '18 at 16:49
  • After doing all the changes you specified, I still can't get it to work. Updated code. The error code is `WSAEINVAL`. – Rokas Višinskas Oct 31 '18 at 19:12
  • Note that you can continue using `recv()` and `send()` in UDP if you call `connect()` first so the socket has a statically assigned peer IP:port. – Remy Lebeau Nov 01 '18 at 07:10
  • @RemyLebeau Note that `connect`ing a UDP socket discards datagrams from other sources. – Maxim Egorushkin Nov 01 '18 at 15:31
  • @Habitate You did not remove `listen` call. And you do not check for errors. – Maxim Egorushkin Nov 01 '18 at 15:33
  • @Habitate you didn't specify which line is failing exactly. – Remy Lebeau Nov 01 '18 at 15:43
  • @MaximEgorushkin yes, I'm aware of that. Once you receive the 1st packet from a new client, you could create a new UDP socket and `connect()` it to that client, then use that socket with `send()` and `recv()` to communicate with just that client. Similar to what the TCP server does when `accept()` returns a newly connected socket. I'm not saying this is ideal for UDP, but it would be a shorter stepping stone when migrating from TCP to UDP without rewriting a bunch of code – Remy Lebeau Nov 01 '18 at 15:44
  • @RemyLebeau In this case you would need a new UDP socket for each client, which is unnecessary. – Maxim Egorushkin Nov 01 '18 at 16:08
  • @MaximEgorushkin I'm not disagreeing with that, and I said as much in my previous comment. I'm just saying this is an *option* to help maintain the *semantics* of the TCP server over UDP, until such time as the UDP server can be rewritten to use UDP more effectively. – Remy Lebeau Nov 01 '18 at 16:25