In TCP socket programming, if recv()
returns 0, it is taken as an indication that the other side closed its connection. However, AFAIK, the TCP RFC does not man
Right, according to POSIX if recv
returns 0
, then the connection is shut down correctly by the peer.
If someone has managed to send a TCP packet with a zero-sized payload, then the OS doesn't have to return any data to the process being blocked on recv
system call on that socket.
Remember that TCP payloads form a continuous stream that may be randomly sliced by the OS, not a sequence of datagrams that must be returned during a single system call.
TCP segments with a payload size of 0 are ubiquitous - they occur in pretty much every real-world TCP stream. They're sent whenever one side wishes to acknowledge reciept of data from the other, but has no data to send of its own. (These are commonly known as "ACK packets", but an "ACK packet" is just a regular segment that happens to contain no data).
Since such packets do not contain any data to deliver to the user application, they will not cause recv()
to return - recv()
will continue blocking until some actual data arrives. If recv()
returns 0, then it is a definite indication that the other end has closed its side of the connection and won't be sending any more data.
Remember that TCP is stream-oriented: there is not a 1-to-1 mapping between the data returned by a single recv()
call and the data in a single TCP segment. A single recv()
call might return a block of data that overlaps several TCP segments, and the data in a single TCP segment might be returned in multiple recv()
calls. The boundaries between TCP segments are not visible to the application using the BSD sockets API. If you want such boundaries, you need to either implement yourself using an application-layer protocol within the TCP stream, or use a datagram-oriented protocol like UDP.