42

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
  • 79,345
  • 17
  • 128
  • 213
iamnp
  • 521
  • 1
  • 4
  • 4
  • 7
    A point of clarification: It's called a TCP segment and a UDP datagram. They are not packets. TCP = Segment, UDP = Datagram, IP = Packet, Ethernet = Frame, At all other layers (AFAIK) they're just called PDU's (Protocol Data Units). – joeqwerty Aug 28 '13 at 04:27

5 Answers5

34

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 TCP. 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 actuality, 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.

David Schwartz
  • 31,215
  • 2
  • 53
  • 82
  • 10
    Might be worth clarifying the last bit for novice readers: *you will see the complete data* **for the datagram in question**. If any one of the split packets gets lost, the datagram is lost and the UDP layer will never know of it. As long as all packets in the datagram are received, they will be assembled at the IP layer and then passed up to the UDP layer. This doesn't preclude the possibility of missing "chunks" in the datastream. Not to be a pedant, but when I was learning this stuff I didn't grok the difference between IP frag and UDP loss until the 2nd or 3rd pass through the textbook. – Justin ᚅᚔᚈᚄᚒᚔ Aug 28 '13 at 15:44
20

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,180
  • 13
  • 16
  • Doesn't the network card driver take care of reassembling up packets not the kernel? – bluehallu Aug 27 '13 at 15:51
  • 2
    @Hallucynogenyc: Unless things have change, Internet protocol is designed to allow packets over 576 bytes to be split up at any point on their journey, but does not expect anything but the final recipient to recombine them. I think the idea is that the use of larger packets was in most cases an effort to reduce overhead; once a packet has been split up at some point on its journey, the overhead has already been incurred so recombining before the final recipient isn't apt to help anything, and may hurt if it has to be re-split. – supercat Aug 27 '13 at 15:55
  • I believe that while any packet which is over 576 bytes may be split, packets which are below that size may not; embedded systems which cannot deal with split packets should avoid asking for anything larger than that. – supercat Aug 27 '13 at 15:57
  • 1
    @mauro.stettler: I've written a TCP stack on "bare metal" (writing the code to talk directly to a number of network interface chip). For hardware that talks to a link with a 576-byte limit to split longer packets is simple. Reassembling packets is *much* more complicated, especially since one may receive pieces of many different packets before any of them is received in full. – supercat Aug 27 '13 at 16:00
  • There is some hope that it won't be split for *tiny* payloads (around 10 or 20 bytes should be ok), because there is a "guaranteed maximum size" required of each **hop** for IP paquets on ipv4 : at least 68 bytes (including IP headers, and not counting lower level headers). see the 1st table in http://en.wikipedia.org/wiki/Maximum_transmission_unit. Different from the 576 bytes of minimal size required from the HOSTS (ie, the originating or end of the transmission, not all the intermediary hops). And carefull: the **payload** is lower still (as each layer's headers take some space). – Olivier Dulac Aug 28 '13 at 08:49
18

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
  • 281
  • 1
  • 2
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
  • 880
  • 5
  • 10
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
  • 487
  • 2
  • 11
  • this is false: if one send a paquet with a 10 or 20 bytes payload, this will generate 1 paquet, and (as I said above), if using ipv4, it should, even when adding all headers of the other protocol layers, fit into within 68 bytes, thus ensuring that it goes through all hops in 1 packet. Tcp stack won't (as is hinted in your 1st paragraph) "wait until the mtu is filled (ie, add several packets to make a properly sized one)" to send a packet!... This behavious would break many things (even if those "fragments" were sent from&to the same pair of hosts) – Olivier Dulac Aug 28 '13 at 17:59
  • @OlivierDulac: That is incorrect. TCP usually generates packets as it needs, trying to optimize network usage, so 20 bytes could end up in two different packets as explained by Kaz. This can be controlled using the [TCP_NODELAY](https://linux.die.net/man/7/tcp) socket option, which disables the Nagles algorithm that dispatches bytes to packets, if your application needs faster TCP networking. Also, 68 bytes is by no means the de-facto standard for packet length: 1500 bytes is a more usual default value (this really varies between networks). – jjmontes Jan 24 '17 at 16:55