dustin ledezma
dustin ledezma

Reputation: 635

C/C++ sockets and a non-blocking recv()

I'm having a problem where calling recv() system call does not block. I have a client-server structure setup at the moment, and the problem I am having is I send the server one message, while the server is set up so that it's something like:

while (1) {
   char buf[1024];
   recv(fd, buf, sizeof(buf), flags);
   processMsg(buf);
}

It receives the first message correctly, but the recv() does not block and "receives" trash data which is not what is desired. I'd like to react to messages only when they are sent. Can anyone advise?

Upvotes: 13

Views: 87950

Answers (3)

Duck
Duck

Reputation: 27542

recv() does not necessarily block until the full request is fulfilled but can return a partial request. The return code will inform you of how many bytes were actually received which can be less than you requested. Even if you specify a MSG_WAITALL flag it can return less due to a signal, etc.

On posix systems, in blocking mode recv will only block until some data is present to be read. It will then return that data, which may be less than requested, up to the amount requested. In non-blocking mode recv will return immediately if there is zero bytes of data to be read and will return -1, setting errno to EAGAIN or EWOULDBLOCK.

The upshot is that normally you will call recv in a loop until you get the amount you want while also checking for return codes of 0 (other side disconnected) or -1 (some error).

I can't speak to windows behavior.

Upvotes: 22

Adam Rosenfield
Adam Rosenfield

Reputation: 400146

There's two possibilities: either an error is occurring, or the socket is set to non-blocking mode. To see if an error is occurring, check the return value of recv:

while() {
    char buf[1024];
    int ret = recv(,buf,,)

    if(ret < 0) {
        // handle error
        printf("recv error: %s\n", strerror(errno));
    } else {
        // only use the first ret bytes of buf
        processMsg(buf, ret);
    }
}

To put the socket into non-blocking mode, or to query if a socket is in non-blocking mode, use fcntl(2) with the O_NONBLOCK flag:

// Test if the socket is in non-blocking mode:
if(fcntl(sockfd, F_GETFL) & O_NONBLOCK) {
    // socket is non-blocking
}

// Put the socket in non-blocking mode:
if(fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK) < 0) {
    // handle error
}

Note that unless you're explicitly changing the blocking behavior, the socket should be blocking by default, so most likely an error is occurring.

Upvotes: 18

ultifinitus
ultifinitus

Reputation: 1883

If you're on windows, run wsagetlasterror() function and look at the return value.

http://msdn.microsoft.com/en-us/library/ms741580%28v=vs.85%29.aspx

If you're on a posix compliant system look at errno

http://pubs.opengroup.org/onlinepubs/009695399/functions/errno.html

Upvotes: 1

Related Questions