0

I am trying to create a UDP client. When I try to send a message to the server I get a WSAEOPNOTSUPP error message. But the subsequent recvfrom call seems to work just fine. I haven't had a chance to test it with the server yet so I'm assuming the data will actually come back as expected. According to the documentation that error means

MSG_OOB was specified, but the socket is not stream-style such as type SOCK_STREAM, OOB data is not supported in the communication domain associated with this socket, or the socket is unidirectional and supports only receive operations.

Here is the code (sanitized for your protection)

WORD version = MAKEWORD(2, 2);
WSADATA data;
int error = 0;

if ((error = WSAStartup(version, &data)) != NO_ERROR)
{
    kzLogError(KZ_LOG_CATEGORY_GENERIC, ("Error: WSAStartup failed with error: {}", error));
    return;
}

if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2)
{
    kzLogError(KZ_LOG_CATEGORY_GENERIC, ("Error: System could not support WinSock 2.2."));

    if (WSACleanup() == SOCKET_ERROR)
    {
        kzLogError(KZ_LOG_CATEGORY_GENERIC, ("Error: Winsock cleanup error: {}", WSAGetLastError()));
    }
    return;
}

SOCKET s = INVALID_SOCKET;

if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
{
    kzLogError(KZ_LOG_CATEGORY_GENERIC, ("Error: Socket creation failed with error: {}", WSAGetLastError()));

    if (WSACleanup() == SOCKET_ERROR)
    {
        kzLogError(KZ_LOG_CATEGORY_GENERIC, ("Error: Winsock cleanup error: {}", WSAGetLastError()));
    }
    return;
}

int bytesRecv = 0;
ReceiveData receiveData;
struct sockaddr_in server_addr;
int server_addr_len = sizeof(server_addr);

memset((char *)&server_addr, 0, server_addr_len);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(2010);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

memset((char *)&receiveData, 0, sizeof(ReceiveData));

if (sendto(s, “hello”, strlen(“hello”), 0, (struct sockaddr *) &server_addr, server_addr_len) == SOCKET_ERROR)
{
    kzLogError(KZ_LOG_CATEGORY_GENERIC, ("Error: unable to send hello to server: {}", WSAGetLastError()));
}

while (bytesRecv != SOCKET_ERROR)
{
    bytesRecv = recvfrom(s, (char*)&receiveData, sizeof(ReceiveData), 0, (struct sockaddr *) &server_addr, &server_addr_len);
    if (bytesRecv > 0)
    {
        // parse the data
    }
    else
    {
        if (bytesRecv == SOCKET_ERROR)
        {
            kzLogError(KZ_LOG_CATEGORY_GENERIC, ("Error: Reading data: {}", WSAGetLastError()));
        }
    }
}

if (closesocket(s) == SOCKET_ERROR)
{
    kzLogError(KZ_LOG_CATEGORY_GENERIC, ("Error: Unable to close socket: {}", WSAGetLastError()));
}

if (WSACleanup() == SOCKET_ERROR)
{
    kzLogError(KZ_LOG_CATEGORY_GENERIC, ("Error: Winsock cleanup error: {}", WSAGetLastError()));
}
cHorse
  • 11
  • 1
  • 8
  • What is the IP address of the server you want to send to, and what IP address have you told your socket to send to ? – nos Oct 16 '18 at 21:03
  • There is some working UDP client-server code here: https://stackoverflow.com/a/51038991/5743288 – Paul Sanders Oct 16 '18 at 21:11
  • @nos This is a connectionless UDP client so in theory it shouldn't care what the server's IP is. `INADDR_ANY` tells the socket to accept data from any IP address communicating over the specified port. – cHorse Oct 16 '18 at 21:14
  • @PaulSanders the code you linked to appears to be doing the same thing I am. And might be a server side implementation. They call `bind` when receiving data from wherever. `sendto` implicitly binds the socket to the port so theoretically I shouldn't need to do that. – cHorse Oct 16 '18 at 21:18
  • 2
    @cHorse Well, but the first thing you do after creating the socket and initialized `server_addr` is a `sendto()` call, so I wonder where you are sending it to when the address is specified as INADDR_ANY. (Indeed, you.can't do that. When you want to send data to a server, you need to specify its address, which for UDP is an IP address and a port number - and when you want to receive data on that socket, whether you define yourself as a client or a server, you have to call bind() first, so your socket gets an address that the peer can send to). – nos Oct 16 '18 at 21:30
  • @nos truthfully I only plan on receiving data from the server not actually send it any. Hence the "hello" message. The only reason I am making the call to `sendto` is because it implicitly binds the socket to the port. If I use `bind` instead `recvfrom` throws a `WSAEINVAL` error. – cHorse Oct 16 '18 at 21:43
  • @cHorse then you are likely using `bind` or `recvfrom` incorrectly. Please show that code – Remy Lebeau Oct 16 '18 at 22:59
  • @RemyLebeau replace the `sendto` in the above code with `bind(s, (SOCKADDR *)&server_addr, sizeof(server_addr))` – cHorse Oct 16 '18 at 23:21
  • @cHorse works fine for me. Please show a [mcve] where it does not work for you. `recvfrom()` would report `WSAEINVAL` if `bind()` failed – Remy Lebeau Oct 17 '18 at 00:30

0 Answers0