45

Can TCP packets arrive to receiver by pieces?

For example, if I send 20 bytes using TCP protocol, can I be 100% sure that I will receive exactly 20 bytes at once, not 10 bytes then another 10 bytes or so?

And the same question for UDP protocol.
I know that UDP is unreliable and packets can not arrive at all or arrive in different order, but what about a single packet? If it arrives, can I be sure that it is a complete packet, not a piece?

voretaq7
  • 80,749
iamnp
  • 551

5 Answers5

37

can TCP packets arrive to receiver by pieces?

Yes. IP supports fragmentation, though TCP generally tries to determine the path MTU and keep its packets smaller than that for performance reasons. Fragmentation increases the datagram loss rate catastrophically. If a path has a 10% packet loss rate, fragmenting a datagram into two packets makes the datagram loss rate almost 20%. (If either packet is lost, the datagram is lost.)

You don't have to worry about this though, and neither does the TCP layer. The IP layer reassembles packets into whole datagrams.

E.g.: if I send 20 bytes using TCP protocol, can I be 100% sure that I will receive exactly 20 bytes at once, not 10 bytes then another 10 bytes or so?

No, but that has nothing to do with packets. TCP is, fundamentally, a byte stream protocol that does not preserve application message boundaries.

And the same question for UDP protocol. I know that UDP is unreliable and packets can not arrive at all or arrive in different order,

The same is true for UDP. Packets are packets. The difference is that TCP has retries and reordering built into the protocol while UDP does not.

but what about 1 packet? If it arrives, can I be sure that it is a complete packet, not a piece?

No, but that's not your problem. The UDP protocol handles datagram reassembly. That's part of its job. (In fact, the IP protocol does this for the UDP protocol, so UDP does it merely by being layered on top of IP.) If a datagram gets split over two packets, the IP protocol will reassemble it for the UDP protocol, so you will see the complete data.

Daniel Chin
  • 103
  • 2
21

You can't be sure that they really physically arrive at once. The Data link layers below TCP/UDP might split your packet up if they want to. Especially if you send data over the internet or any networks outside of your control it's hard to predict that.

But no matter if the data arrives in one packet or multiple packets at the receiver. The OS should abstract the concatenation of these packets, so for your application it still looks like everything arrived at once. So, unless you are a kernel hacker, in most cases you don't need to worry if this data is transferred in one or many packets.

For UDP the OS will also do some abstraction, so the application that receives the data doesn't have to know in how many packets the data has been transmitted. But the difference to TCP is that there is no guarantee for the data to actually arrive. It's also possible that the data get's split up into multiple packets, and some of them arrive and some don't. For the receiving application it just looks like a stream of data anyway, no matter if it's complete or not.

replay
  • 3,310
20

Examples. Blocks of contiguous characters correspond to send() calls:

TCP:

Send: AA BBBB CCC DDDDDD E         Recv: A ABB B BCC CDDD DDDE

All data sent is received in order, but not necessarily in the same chunks.

UDP:

Send: AA BBBB CCC DDDDDD E         Recv: CCC AA E

Data is not necessarily in the same order, and not necessarily received at all, but messages are preserved in their entirety.

Jim Cote
  • 301
6

E.g.: if I send 20 bytes using TCP protocol, can I be 100% sure that I will receive exactly 20 bytes at once, not 10 bytes then another 10 bytes or so?

No, TCP is a stream protocol, it keeps data in order but it doesn't group it by message. On the other hand UDP is message-oriented, but unreliable. SCTP has the best of both worlds but isn't natively usable because NATs break the Internet.

Changaco
  • 890
1

There is some assurance that if you send 20 bytes at the very beginning of a TCP stream, it will not arrive as two 10 byte pieces. This is because TCP stack will not send such small segments: there is a minimum MTU size. However, if the send is anywhere in the middle of a stream, all bets are off. It could be that your protocol stack takes 10 byte of the data to fill a segment and send it out, and then then next ten bytes go to another segment.

Your protocol stack breaks data into chunks and places them into a queue. The chunk sizes are based on the path MTU. If you perform a send operation, and there is still queued data pending, the protocol stack will typically peek at the segment which is at the tail of the queue and see whether there is room in that segment to add more data. The room could be as small as one byte, so even a two-byte send could be broken into two.

On the other end, the segmentation of data means that there can be partial reads. A receive operation can potentially wake up and obtain data when as few as one segment arrives. In the widely implemented sockets API, a receive call can ask for 20 bytes, but it could return with 10. Of course, a buffering layer can be built on it which will block until 20 bytes are received, or the connection breaks. In the POSIX world, that API can be the standard I/O streams: you can fdopen a socket descriptor to obtain a FILE * stream, and you can use fread on it to fill a buffer such that the full request is satisfied with as many read calls as it takes.

UDP datagrams frame the data. Each send call generates a datagram (but see below about corking). The other side receives a full datagram (and, in the socket API, it must specify a buffer large enough to hold it, or else the datagram will be truncated). Large datagrams get fragmented by IP fragmentation, and are re-assembled transparently to applications. If any fragment is missing, the entire datagram is lost; there is no way to read partial data in that situation.

There exist extensions to the interface allowing multiple operations to specify a single datagram. In Linux, a socket can be "corked" (prevented from sending). While it is corked, written data is assembled into a single unit. Then when the socket is "uncorked", a single datagram can be sent.

Kaz
  • 497