Search code examples
csocketstcp

tcp send and recv: always in loops?


What are the best practices when sending (or writing) and recving (or reading) to/from a TCP socket ?

Assume usual blocking I/O on sockets. From what I understand :

  • writing (sending) should be fine without a loop, because it will block if the write buffer of the socket is full, so something like
    if ((nbytes_w = write(sock, buf, nb)) < nb)
         /* something bad happened : error or interrupted by signal */
    
    should always be correct ?
  • on the other hand, there is no guaranty that one will read a full message, so one should read with
    while ((nbytes_r = read(sock, buf, MAX)) > 0) {
        /* do something with these bytes */
        /* break if encounter specific application protocol end of message flag
           or total number of bytes was known from previous message
           and/or application protocol header */
    } 
    
    

Am I correct ? Or is there some "small message size" or other conditions allowing to read safely outside a loop ?

I am confused because I have seen examples of "naked reads", for instance in Tanenbaum-Wetherall:

read(sa, buf, BUF_SIZE); /* read file name in socket */

Solution

  • Yes you must loop on the receive

    Once a week I answer a question where someones TCP app stops working for this very reason. The real killer is that they developped the client and server on the same machine, so they get loopback connection. Almost all the time a loopback will receive the send messages in the same blocks as they were sent. This makes it look like the code is correct.

    The really big challenge is that this means you need to know before the loop how big the message is that you are going to receive. Possibilities

    • send a fixed length length (ie you know its , say, 4 bytes) first.
    • have a recognizable end sequence (like the double crlf at the end of an HTTP request.
    • Have a fixed size message

    I would always have a 'pull the next n bytes' function.

    Writing should loop too, but that easy, its just a matter of looping.