Visual C++ Network: Does one call to 'send()' result in one call to 'recv()'?
Q: Does one call to 'send()' result in one call to 'recv()'?
A: In short, the answer is: not necessarily. A socket of type 'SOCK_STREAM' uses the TCP/IP protocol for data transfer. And one of the important things to understand is that TCP is not a message-oriented protocol - it is stream-based. Due to this, it does not preserve message boundaries. This is an important point which is very often missed or overlooked by many programmers (especially by those dealing with sockets the first time).
Consider the following scenario:
A sender sends data in chunks of 50, 50 and 100 bytes to a receiver, calling the function 'send()' three times (we simply assume here that each function call will send the data in one chunk although this is not guaranteed). On the server side, the data will not necessarily be received in chunks of 50, 50 and 100 bytes, calling the function 'recv()' three time (although it is possible). All bytes may be received within one single function call, resulting in a 200-byte chunk. They may also be received in two chunks of 70 and 130 bytes.
If only the first 50 bytes of the first chunk will be inspected and the first 50 bytes of the second chunk, it will result in data garbage, since the 20 bytes of the first chunk have been ignored.
There are many factors that contribute to this kind of behavior. The major reason is because of the optimization to reduce the protocol and processing overhead. Client/server applications should be programmed keeping the above in mind. Unfortunately, at the time of testing the application, it may incidentally happen that one 'recv()' call will receive all the bytes issued by one 'send()' call. However, as being pointed out, this is not guaranteed.
Some programmers request to re-send the data when they get caught in the above trap. However, this kind of programming style is unnecessary in regard to one of the major advantages of TCP - the guaranteed delivery of all the data.
There are many ways to get around these pitfalls while dealing with sockets and TCP such as using delimiters or fixed length data. Another solution is to ‘packetize’ the data. You can find a detailed discussion in the following FAQ 'How do I impose a packet scheme?'. But the most important point is that one should always check the return value of 'recv()' to see how many bytes have been received. If the value is less than the expected amount, another call to 'recv()' can be issued and so on until everything have been received.
As a final note, the same behavior applies to the 'send()' function as being shown in the FAQ "When does 'send()' return?"...
A special thanks to Mr. Andreas Masur for his help with this FAQ.