Case when blocking recv() returns less than requested bytes

Adil picture Adil · Feb 19, 2010 · Viewed 9k times · Source

The recv() library function man page mention that:

It returns the number of bytes received. It normally returns any data available, up to the requested amount, rather than waiting for receipt of the full amount requested.

If we are using blocking recv() call and requested for 100 bytes:

recv(sockDesc, buffer, size, 0); /* Where size is 100. */

and only 50 bytes are send by the server then this recv() is blocked until 100 bytes are available or it will return receiving 50 bytes.

The scenario could be that:

  • server crashes after sendign only 50 bytes

  • bad protocol design where server is only sending 50 bytes while client is expecting 100 and server is also waiting for client's reply (i.e. socket close connection has not been initiated by server in which recv will return)

I am interested on Linux / Solaris platform. I don't have the development environment to check it out myself.

Answer

nos picture nos · Feb 19, 2010

recv will return when there is data in the internal buffers to return. It will not wait until there is 100 bytes if you request 100 bytes.

If you're sending 100 byte "messages", remember that TCP does not provide messages, it is just a stream. If you're dealing with application messages, you need to handle that at the application layer as TCP will not do it.

There are many, many conditions where a send() call of 100 bytes might not be read fully on the other end with only one recv call when calling recv(..., 100); here's just a few examples:

  • The sending TCP stack decided to bundle together 15 write calls, and the MTU happened to be 1460, which - depending on timing of the arrived data might cause the clients first 14 calls to fetch 100 bytes and the 15. call to fetch 60 bytes - the last 40 bytes will come the next time you call recv() . (But if you call recv with a buffer of 100 , you might get the last 40 bytes of the prior application "message" and the first 60 bytes of the next message)

  • The sender buffers are full, maybe the reader is slow, or the network is congested. At some point, data might get through and while emptying the buffers the last chunk of data wasn't a multiple of 100.

  • The receiver buffers are full, while your app recv() that data, the last chunk it pulls up is just partial since the whole 100 bytes of that message didn't fit the buffers.

Many of these scenarios are rather hard to test, especially on a lan where you might not have a lot of congestion or packet loss - things might differ as you ramp up and down the speed at which messages are sent/produced.

Anyway. If you want to read 100 bytes from a socket, use something like

int
readn(int f, void *av, int n)
{
    char *a;
    int m, t;

    a = av;
    t = 0;
    while(t < n){
        m = read(f, a+t, n-t);
        if(m <= 0){
            if(t == 0)
                return m;
            break;
        }
        t += m;
    }
    return t;
}

...

if(readn(mysocket,buffer,BUFFER_SZ) != BUFFER_SZ) {
  //something really bad is going on.

}