tags:

views:

89

answers:

2

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 dont have the development environment to check it out myself.

+5  A: 

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.

}
nos
Thanks for detailed explanation. Just confirming if this is true for *blocking* recv() call as well? (i.e. recv() return with less than requested bytes)
Adil
Yes, this is true for a blocking recv call.
nos
+3  A: 

The behavior is determined by two things. The recv low water mark and whether or not you pass the MSG_WAITALL flag. If you pass this flag the call will block until the requested number of bytes are received, even if the server crashes. Other wise it returns as soon as at least SO_RCVLOWAT bytes are available in the socket's receive buffer.

SO_RCVLOWAT

Sets the minimum number of bytes to process for socket input operations. The default value for SO_RCVLOWAT is 1. If SO_RCVLOWAT is set to a larger value, blocking receive calls normally wait until they have received the smaller of the low water mark value or the requested amount. (They may return less than the low water mark if an error occurs, a signal is caught, or the type of data next in the receive queue is different than that returned, e.g. out of band data). This option takes an int value. Note that not all implementations allow this option to be set.

Robert S. Barnes
SO_RCVLOWAT is socket option. if we have not set any socket option and no flag is passed to recv(), and blocking recv() call is issued, will it wait for all the requested bytes? (The socket close operation has not been initaited as well)
Adil
In the situation you describe in your post it will return 50 bytes. It will **not** wait for the full 100 bytes unless you pass the `MSG_WAITALL` flag to `recv`.
Robert S. Barnes