Same network, two opposite bets
In the previous guide you saw how ports and sockets let one host run many conversations at once, and how the transport layer is the first layer that talks process-to-process rather than host-to-host. But the transport layer offers two very different products built on top of that same idea, and the whole point of this guide is to understand why both exist. They are UDP (the User Datagram Protocol) and TCP (the Transmission Control Protocol).
Here is the crucial backdrop. The network layer underneath both of them — IP — promises almost nothing. It will try its hardest to carry a packet to the destination, but packets can be lost, duplicated, reordered, or quietly corrupted along the way. We call this a best-effort service, and it is a deliberate design choice: keeping the core dumb and simple is exactly what let the Internet scale. So the transport layer's job is to decide how much, if anything, to do about that unreliability — and UDP and TCP answer that question in opposite ways.
This split is the end-to-end principle in action: rather than build reliability into every switch in the best-effort core, push the cleverness out to the two end hosts, and let each application choose how much of it it wants. UDP says "give me the bare minimum." TCP says "give me the full treatment." Neither is the broken version of the other; they are two finished tools for two different jobs.
UDP: the thin, honest wrapper
UDP is almost shockingly simple. It takes your message, slaps on a tiny 8-byte header, and hands it to IP. That header carries just four things: the source port, the destination port, a length, and a checksum (an optional error-detecting code over the data). That is the entire protocol. UDP is connectionless — there is no setup conversation, no handshake; you just send. It does no retransmission, keeps no ordering, and makes no promise that your message arrives at all. People call this best-effort delivery: it will try, and that is all.
The one real service UDP adds over raw IP is multiplexing: the two port numbers let the receiving host hand the message to the right process, exactly as the previous guide described. Everything else, UDP deliberately leaves out. And that omission is the feature. If your application can tolerate the odd lost message but cannot tolerate waiting, UDP's thinness is a gift.
Who wants that? Live voice and video — VoIP and video calls — would rather skip a tiny glitch than freeze the whole call waiting for one re-sent packet that is already too late to play. The DNS lookups you traced in an earlier rung fire one tiny request and want one tiny reply with no setup cost. Online games send a flood of position updates where only the newest matters. For all of these, the careful machinery of TCP would actively hurt, and UDP is the right, deliberate choice — not a broken one.
TCP: a reliable, ordered byte stream
TCP makes the opposite bet: take that same unreliable IP underneath and build, on top of it, the illusion of a perfect pipe. When you write data into a TCP connection at one end, the exact same bytes come out the other end, in the exact same order, with nothing missing and nothing duplicated. This is the byte stream abstraction: you do not send messages, you write into a stream, like pouring water into a hose. TCP itself decides how to chop that stream into chunks called segments for the trip, and the receiver reassembles them so seamlessly the application never sees the seams.
How does it pull off reliability over an unreliable network? With a small set of mechanisms that combine into reliable data transfer — the engine the very next guide takes apart bolt by bolt. In brief: every byte gets a sequence number so the receiver can detect gaps and reorder; the receiver sends back an acknowledgment (an ACK) saying "I have everything up through byte N"; a retransmission timer fires if an ACK does not come back in time, triggering a resend; and a checksum catches corruption. Loss, reorder, duplication, corruption — each has a remedy.
Because TCP is connection-oriented, the two ends first run a setup conversation — the famous three-way handshake, a "can you hear me? — yes, can you? — yes" in the form SYN, SYN-ACK, ACK — to agree on starting sequence numbers before any real data flows. They later tear the connection down cleanly when finished. Those two ceremonies, and what the handshake really does (it synchronizes sequence numbers; it is not authentication), are the whole topic of guide 4 in this rung.
UDP datagram TCP segment
+----------------+ +------------------------+
header: | src port | | src port | dst port |
(8 bytes | dst port | | sequence number |
for UDP, | length | | acknowledgment number |
20+ bytes | checksum | | flags (SYN/ACK/FIN..) |
for TCP) +----------------+ | receive window | chksum |
| your data... | +------------------------+
+----------------+ | your data... |
+------------------------+
UDP: 4 fields, then go. TCP: seq#, ack#, window, flags -> reliability.Flow control: don't drown the receiver
Reliability is not TCP's only job. Imagine a fast server blasting data at a tiny sensor that reads slowly. Even if every byte arrives perfectly, the sensor's receive buffer would overflow and the surplus would be dropped — reliable delivery into a bucket with no bottom. Flow control is TCP's fix: the receiver constantly tells the sender how much free buffer space it currently has, in a field called the receive window carried in every ACK. The sender promises never to have more unacknowledged data in flight than that window allows.
It works like a sliding window. Say the receiver advertises a window of 4000 bytes. The sender may have at most 4000 bytes outstanding (sent but not yet ACKed). As ACKs come back, the window slides forward and more may be sent; if the application on the receiving side is slow to read, the advertised window shrinks, even to zero, and the sender pauses. This is the sliding window you will meet again as the heart of reliable transfer — here it is being used purely to match the sender's pace to the receiver's.
The hidden cost: head-of-line blocking
TCP's strict in-order delivery has a sharp edge worth naming, because it explains a lot of modern protocol design. Since TCP must hand bytes to the application in order, a single lost segment stalls everything behind it. Suppose segments 1, 2, 3, 4 are sent and only segment 2 is lost. Segments 3 and 4 arrive safely — but TCP cannot deliver them yet, because byte order must be preserved. They wait, fully received, until segment 2 is retransmitted and arrives. That stall is head-of-line blocking: the one item at the front of the line freezes everyone behind it.
This stings most when one TCP connection carries many independent streams. Loading a web page pulls dozens of files; if they share one connection, a single lost packet on file A needlessly stalls files B, C, and D, which had nothing to do with the loss. This exact pain pushed the design of QUIC, a newer transport that runs over UDP and rebuilds reliability per-stream, so a loss in one stream no longer blocks the others. HTTP/3 is simply HTTP carried over QUIC, and it exists in large part to escape TCP's head-of-line blocking. UDP, ironically, became the foundation for the next reliable protocol.
One last honesty check before you climb on. TCP gives you reliable, ordered bytes — but reliable does not mean secure, and TCP encrypts nothing by itself. An eavesdropper on the path can read every byte. Confidentiality and authentication come from TLS layered on top, which is a separate guide in a later rung. Keep these axes apart in your head: reliability is about loss and order; security is about secrecy and identity. TCP buys you the first; it buys you none of the second.