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.