38

I am creating a UDP socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP) via Winsock and trying to recvfrom on this socket, but it always returns -1 and I get WSAEINVAL (10022). Why?

When I bind() the port, that does not happen, but I have read that it is very lame to bind the client's socket.

I am sending data to my server, which answers, or at least, tries to.

Inc::STATS CConnection::_RecvData(sockaddr* addr, std::string &strData)
{
    int ret;            // return code
    int len;            // length of the data
    int fromlen;        // sizeof(sockaddr)
    char *buffer;       // will hold the data
    char c;

    //recv length of the message
    fromlen = sizeof(sockaddr);
    ret = recvfrom(m_InSock, &c, 1, 0, addr, &fromlen);
    if(ret != 1)
    {
#ifdef __MYDEBUG__
        std::stringstream ss;
        ss << WSAGetLastError();
        MessageBox(NULL, ss.str().c_str(), "", MB_ICONERROR | MB_OK);
#endif
        return Inc::ERECV;
    }
    ...

This is a working example I wrote a few moments ago, and it works without the call to bind() in the client:

#pragma comment(lib, "Ws2_32.lib")

#define WIN32_LEAN_AND_MEAN

#include <WS2tcpip.h>
#include <Windows.h>
#include <iostream>

using namespace std;

int main()
{
    SOCKET sock;
    addrinfo* pAddr;
    addrinfo hints;
    sockaddr sAddr;
    int fromlen;
    const char czPort[] = "12345";
    const char czAddy[] = "some ip";

    WSADATA wsa;
    unsigned short usWSAVersion = MAKEWORD(2,2);

    char Buffer[22] = "TESTTESTTESTTESTTEST5";
    int ret;

    //Start WSA
    WSAStartup(usWSAVersion, &wsa);

    //Create Socket
    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    //Resolve host address
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_protocol = IPPROTO_UDP;
    hints.ai_socktype = SOCK_DGRAM;

    if(getaddrinfo(czAddy, czPort, &hints, &pAddr))
    {
        std::cerr << "Could not resolve address...\n";
        std::cin.get();
        return 1;
    }

    //Start Transmission
    while(1)
    {
        ret = sendto(sock, Buffer, sizeof(Buffer), 0, pAddr->ai_addr,
                     pAddr->ai_addrlen);
        if(ret != sizeof(Buffer))
        {
            std::cerr << "Could not send data\n";
            std::cin.get();
            return 1;
        }

        fromlen = sizeof(SOCKADDR);
        ret = recvfrom(sock, Buffer, sizeof(Buffer), 0, &sAddr, &fromlen);
        if(ret != sizeof(Buffer))
        {
            std::cout << "Could not receive data -  error: " << 
                          WSAGetLastError() << std::endl;
            std::cin.get();
            return 1;
        }

        Buffer[ret-1] = '\0';
        std::cout << "Received: " << Buffer << std::endl;
    }
    return 0;
}
Warren Young
  • 40,875
  • 8
  • 85
  • 101
Juarrow
  • 2,232
  • 5
  • 42
  • 61

5 Answers5

60

With UDP, you have to bind() the socket in the client because UDP is connectionless, so there is no other way for the stack to know which program to deliver datagrams to for a particular port.

If you could recvfrom() without bind(), you'd essentially be asking the stack to give your program all UDP datagrams sent to that computer. Since the stack delivers datagrams to only one program, this would break DNS, Windows' Network Neighborhood, network time sync....

You may have read somewhere on the net that binding in a client is lame, but that advice only applies to TCP connections.

Warren Young
  • 40,875
  • 8
  • 85
  • 101
  • Well... But I am creating a port, which I am receiving from. I am not telling the OS to send me a message , when anywhere on any port is any data... I am making a call to ask for it... Since I am able to grab all the data on the port, this should be sufficient, in my eyes – Juarrow Jun 16 '10 at 23:34
  • 3
    Without seeing your code, I can only guess, but I think you're putting the port number in the structure you pass for the "from" parameter. That doesn't help. That parameter isn't read by the stack, it is only written to, so your program can know who sent the datagram. Observe that it's optional, so you can pass 0 here, so again you're back to the same situation as before, where the stack has to have some way to know which program to deliver a datagram to based solely on the port number it came in on. That's what bind() does: it associates a program with a port. – Warren Young Jun 17 '10 at 00:10
  • http://codepad.org/4ZmoP4K5 <- this is the responsible code piece (I still don´t know how to show code in here , so i paste it on codepad)... the addr pointer points to an valid sockaddr*, and m_InSock was successfully initialized... (As I mentioned before, I already did send data that has been received...) But I am sure, that it should work for the client without the bind(), because i tried and example from a tutorial, which worked... – Juarrow Jun 17 '10 at 00:47
  • Nowhere in that code snippet is the UDP port number you want the stack to give you datagrams for. You need the bind() call to set up the association between the UDP port number and your program. – Warren Young Jun 17 '10 at 01:27
  • Hmmm... But why does it work without?... I wrote a small test client and an test server, to prove that the client can send and receive without bindig the socket... I posted the code above in an edit in my original post. I´m totally confused now :/... – Juarrow Jun 17 '10 at 07:39
  • Awww.... I read the remarks section of the recvfrom function again and now all You wrote makes sense to me :D... sendto implicitly binds the socket... I´m sorry if I were a chunky student^^... Thank´s to both of You:)... – Juarrow Jun 17 '10 at 08:38
  • 2
    I wouldn't say that sendto() binds the socket, but it is true that you don't have to bind() to use sendto(). recvfrom() is different because of UDP's connectionless nature. In essence, a program using recvfrom() is a "server" even if you think of it as a client, because like a TCP server, a program that calls recvfrom() has to sit waiting for data from any possible sender. – Warren Young Jun 17 '10 at 17:17
  • 1
    @WarrenYoung, your comment "the stack delivers datagrams to only one program" is incorrect. Datagrams are delivered to as many programs as are bound to the corresponding port. By default, only a single program can bind the a given port. However, calling setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) before bind allows multiple binders and so a single UDP datagram can be delivered to many programs that are listening for it. – user1775138 Nov 25 '19 at 13:10
54

Your other code sample works because you are using sendto before recvfrom. If a UDP socket is unbound and either sendto or connect are called on it, the system will automatically bind it for you and thus the recvfrom call later on will succeed. recvfrom will not bind a socket, as this call expects the socket to have been bound already, or an error will be thrown.

Ajay
  • 18,086
  • 12
  • 59
  • 105
Mecki
  • 125,244
  • 33
  • 244
  • 253
  • Are you sure that connect will also try to bind the unbound UDP socket ? Another SO thread https://stackoverflow.com/questions/4487002/problem-using-connect-send-recv-with-udp-sockets/19368670#19368670 indicates that explicit bind is required for UDP socket to receive data. – FaceBro Jun 20 '17 at 04:02
  • 1
    @FaceBro Yes, I am sure, as the typical way to find out which local IP address a system will use when sending data to a specific dest IP address is the following: Make a new UDP socket, connect it to the dest IP, query its local IP. And querying the local IP only works when a socket is bound as binding is the operation that gives a socket a local IP. – Mecki Jun 20 '17 at 09:15
6

I had the same problem a few weeks ago, the following remarks helped me to understand whether an explicit bind() call is necessary:

recvfrom function (MSDN)

Explicit binding is discouraged for client applications. For client applications using this function, the socket can become bound implicitly to a local address through sendto, WSASendTo, or WSAJoinLeaf.

sendto function (MSDN)

Note If a socket is opened, a setsockopt call is made, and then a sendto call is made, Windows Sockets performs an implicit bind function call. If the socket is unbound, unique values are assigned to the local association by the system, and the socket is then marked as bound.

  • Bug the first remark says "Explicit binding is discouraged for client applications". Why this? What is the right solution in this case? If I have a client that needs to connect and start receving data without sending anityhing, what should I do? – Magallo May 13 '15 at 09:15
  • It's been a while but here is an [answer](https://www.gamedev.net/topic/252865-recvfrom-and-bind-questions/) to a similar question which I found back then. –  May 13 '15 at 17:32
1

Here it says the following:

Parameters

s [in]: A descriptor identifying a bound socket.

...

Return Value

WSAEINVAL: The socket has not been bound with bind, or an unknown flag was specified, or MSG_OOB was specified for a socket with SO_OOBINLINE enabled, or (for byte stream-style sockets only) len was zero or negative.

As far as I remember bind is not required for a UDP socket because a bind call is made for you by the stack. I guess it's a Windows thing to require a bind on a socket used in a recvfrom call.

Eugen Constantin Dinca
  • 8,994
  • 2
  • 34
  • 51
  • Ye, i agree with You... I am wondering, why that is ,too... I never had to do it in the last windows-programms i made... – Juarrow Jun 16 '10 at 21:23
  • Can you post some code? Perhaps there's another parameter of recvfrom that's causing this. Ans also what version of Windows are you're using? – Eugen Constantin Dinca Jun 16 '10 at 21:26
  • Inc::STATS CConnection::_RecvData(sockaddr* addr, std::string strData) { int ret, len, fromlen; //return code / length of the data / sizeof(sockaddr) char *buffer; //will hold the data char c; //recv length of the message fromlen = sizeof(sockaddr); ret = recvfrom(m_InSock, &c, 1, 0, addr, &fromlen); if(ret != 1) { – Juarrow Jun 16 '10 at 23:30
  • Add the code to your question to be able to properly format it. – Eugen Constantin Dinca Jun 17 '10 at 00:47
  • added the code above and added another working example i´ve written shortly, too... – Juarrow Jun 17 '10 at 07:42
  • recvfrom won't bind a socket, it has to be bound already for this call to succeed. An UDP socket is automatically bound by the system if you either connect it to a destination address or send any data to it using sendto. – Mecki Jan 09 '13 at 17:58
-2

If you want your socket to be bound to some local port selected automatically by a system, you can call bind(sock, &sa, sa_len) with a zeroed sockaddr. Just set the family you need. It would default-bind a socket to some port selected by the system.

sockaddr_in sa = {};
sa.sin_family = AF_INET;
const int res = ::bind(socket_id, (sockaddr*) &sa, sizeof sa);
if (res < 0)
{
    std::cerr << "UDP binding has failed\n";
    return;
}
maxlovic
  • 67
  • 5
  • 1
    This is not an answer to the very old original question and was already mentioned by @WarrenYoung – Juarrow Jul 15 '22 at 14:40