Skip to main content

TCP vs UDP

Introduction

In the last lesson you followed a packet across the planet and watched it arrive at exactly the right machine and the right program. Here's the part nobody mentioned: the network never promised it would get there. The internet's job — moving packets — is best-effort. Packets get lost when a router is overwhelmed, arrive out of order because they took different paths, or occasionally show up twice. The wire shrugs and moves on.

So somebody has to decide what to do about that mess — and that somebody is Layer 4, the transport layer. It sits between the raw, unreliable packet delivery below and your application above, and it offers you a choice between two protocols with opposite philosophies:

TCP hands you a reliable, ordered stream — nothing lost, nothing out of order — but makes you pay for every guarantee. UDP hands you a fast, bare pipe — no promises — and gets out of your way.

The one idea that unlocks this entire lesson, and that you should tattoo on your brain for system design, is this: guarantees cost round-trips. Every promise TCP makes — I'll set up a connection, I'll confirm you got it, I'll resend what's missing, I'll keep it in order — is bought with a round-trip across the network, an extra header, or a deliberate pause. UDP refuses to pay any of it, which makes it lean and instant and completely unguaranteed. By the end you'll know exactly which bill is worth paying for which job — and why the "right" choice flips depending on whether your app needs its data complete or needs it fresh.

Illustration comparing TCP and UDP as two ways to send data across a network. TCP is drawn as a reliable ordered stream: it begins with a three-way handshake — SYN, SYN-ACK, ACK — that costs about one round trip before any data is sent, then sends numbered segments that the receiver acknowledges, and when a segment is lost it is retransmitted while later segments wait in a buffer so everything is delivered complete and in order but later, which is head-of-line blocking. UDP is drawn as a fast best-effort pipe: no handshake, an eight-byte header, datagrams fired immediately, and a lost datagram is simply gone and never resent, so delivery is instant but may have gaps and arrive out of order. A central dial shows the core trade-off between reliability and ordering on one side and latency and low overhead on the other, with the thesis that every guarantee TCP provides is paid for in round trips, header bytes, or stalls. A comparison strip shows the header sizes, about twenty bytes for TCP versus eight for UDP, and that TCP is a byte stream with no message boundaries while UDP preserves datagram boundaries. A usage strip lists who uses which: TCP for the web, email, databases, and SSH where everything must arrive; UDP for DNS, live video and voice, and online games where fresh data beats complete data, since a retransmitted video frame or game position from the past is useless. Finally it teases QUIC and HTTP/3, which rebuild reliability on top of UDP per stream to escape TCP's head-of-line blocking with a faster handshake.

TCP: The Reliable Stream

TCP — the Transmission Control Protocol — is the one that makes promises, and it keeps a remarkable number of them. The best way to feel what TCP is like is to think of a phone call: you say "hello?" and wait for "hi, I can hear you" before you start talking, you speak in order, you get little confirmations that you're being heard, and the instant the line drops you both know. TCP is that, for data. Concretely, it gives you four guarantees:

  • A connection. Before any data flows, the two sides establish a connection and agree they're both ready. TCP is connection-oriented — there's a real, shared understanding between the two endpoints, not just packets flung into the void.
  • Reliability. Every byte is numbered, and the receiver acknowledges what it got. If something goes missing, the sender notices (the acknowledgment never comes) and retransmits it. Data gets there, or TCP keeps trying — and if it truly can't, it tells you the connection failed.
  • Ordering. Packets that arrive out of order are held in a buffer and reassembled, so your application always reads the bytes in the exact order they were sent. A jumbled arrival becomes a clean, in-order stream.
  • Not overwhelming anyone. TCP practices flow control (don't send faster than the receiver can accept) and congestion control (don't send faster than the network can carry — back off when the path is congested). It's a polite protocol that shares the road.

One subtle but important detail: TCP gives you a byte stream, not messages. It doesn't preserve the boundaries of your send() calls — two messages can arrive glued together or split across reads. If your application needs to know where one message ends and the next begins, you have to mark that yourself (a length prefix, a delimiter). TCP guarantees the bytes, in order — it just doesn't guarantee your notion of a message. That's the reliable stream. Now the catch: none of it is free.

The Handshake, and the Bill for Every Promise

Watch how TCP starts a conversation, because the cost of its guarantees is right there in the opening move. Before a single byte of your request goes out, the two sides perform the three-way handshake:

  1. SYN — the client says "I'd like to talk; here's my starting sequence number."
  2. SYN-ACK — the server replies "got it, I'm ready; here's mine."
  3. ACK — the client says "great, let's go" — and now it can send the request.

That's a full round trip across the network before your request even leaves. On a fast local link it's nothing; on a mobile connection to a server an ocean away — say a 200-millisecond round trip — it's 200 milliseconds of pure waiting before you've sent anything, and roughly 1.5 round trips before the first byte of the response comes back. And that's just TCP — if the connection is encrypted, TLS adds more round-trips on top (that's a later lesson).

This is the whole thesis made concrete: guarantees cost round-trips. Reliability costs the acknowledgments flowing back and the resends when they don't. Ordering costs the buffering and the stalls. Connection setup costs the handshake. Congestion control costs a cautious, ramp-up start. Every single promise TCP makes shows up as latency, extra header bytes (~20 of them per segment, versus UDP's 8), or a pause. For a big file download or a bank transaction, that bill is absolutely worth paying — you'd rather wait than lose data. But it is a bill. And sometimes you'd rather not pay it at all — which is the entire reason UDP exists.

UDP: The Fast, Bare Pipe

UDP — the User Datagram Protocol — is the one that makes no promises, and that turns out to be exactly what some applications want. If TCP is a phone call, UDP is shouting a message across a courtyard, or dropping a stack of postcards in the mail: you fire it off and hope. No "can you hear me," no confirmation, no guarantee it arrives, no guarantee of order. Here's what UDP gives you — and, more tellingly, what it doesn't:

  • No handshake. UDP is connectionless. You send a packet immediately — there's no round-trip of setup, no state to establish. First byte goes out now.
  • No reliability. A lost datagram is simply gone. UDP will not notice, will not retransmit, will not tell you. Best-effort means send it and move on.
  • No ordering. Datagrams arrive in whatever order the network delivers them. UDP won't reorder them for you.
  • No flow or congestion control. UDP will happily fire as fast as you tell it to, whether or not the receiver or the network can keep up.

What you get in return is speed and a tiny footprint: an 8-byte header (versus TCP's 20+) that carries basically just the ports and a checksum, no setup latency, and no stalls. One more nice property, opposite to TCP: UDP preserves message boundaries — one send is one datagram, delivered whole or not at all — so you always know where a message starts and ends.

It's tempting to read that list of "no, no, no" as UDP being a broken, worse TCP. It isn't. UDP is a blank, fast pipe, and its lack of guarantees is the feature. It hands you the raw ability to move packets with minimal delay and then says: whatever reliability you actually need, you build — and only what you need. For a whole class of applications, that's not a limitation. It's the point. Let's watch the two react to trouble side by side.

See It: Both Protocols Under Fire

The difference between TCP and UDP only becomes visceral when packets start dropping — so let's break the network on purpose and watch each one react. Below, the same numbered messages travel down two lanes at once.

Cause some damage: drag the loss slider up, or click a packet in flight to drop it, and watch the two philosophies play out in real time. TCP does its handshake first (there's your round-trip of setup), then retransmits anything it loses and holds later packets in the buffer until the gap is filled — so it always finishes complete and in order, but late. That pause where arrived-but-undeliverable packets pile up waiting for one straggler? That's head-of-line blocking, live. UDP fires with no handshake and simply loses whatever drops — instant, but with holes.

Then do the thing that makes this lesson click: flip the workload between a FILE and a LIVE VIDEO. Watch the verdict flip with it. For the file, TCP's completeness is obviously right. For the video, TCP's retransmit proudly delivers a frame from the past — useless, and it stalled everything to do it — while UDP's little gap barely registers. Same packet loss, opposite right answer. That's the whole reason both protocols exist.

TCP vs UDP Under Fire. Send the same numbered messages down both lanes and then break the network: drag the loss slider, or click a packet in flight to drop it. Watch TCP do its handshake, then retransmit anything lost and hold later packets in order — so it arrives complete, but late (that stall is head-of-line blocking). Watch UDP fire with no handshake and simply lose what drops — instant, but with gaps. Then flip the workload between a FILE and a LIVE VIDEO and watch the verdict flip with it: for a file, complete wins; for live video, a resent frame from the past is useless, so fresh wins. Same loss, opposite right answer — that is the whole lesson.

Head-of-Line Blocking: The Price of Order

The stall you just watched deserves its own name and a moment of attention, because it's one of the most important — and most counterintuitive — costs in all of networking. It's called head-of-line (HoL) blocking, and it's the direct price of TCP's in-order guarantee.

Picture a single-file checkout line. The person at the front is fumbling for their wallet. Everyone behind them is ready to pay in two seconds flat — but it doesn't matter, because the line is strictly ordered and nobody can move until the front clears. That's exactly what happens inside TCP: if segment #4 is lost, then segments #5, #6, and #7 can arrive safely and sit in the receiver's buffer — but TCP refuses to hand any of them to your application until #4 is retransmitted and slots into place, because it promised in-order delivery. Data that already made it is held hostage by one straggler.

This gets genuinely painful when you multiplex — when you run many independent streams over one TCP connection, which is exactly what HTTP/2 does to load a web page's dozens of resources at once. Because TCP sees only a single ordered byte stream and has no idea those streams are independent, one lost packet stalls all of them. Your CSS file is held up because an unrelated image's packet went missing. The ordering guarantee, so valuable for a single file, becomes a bottleneck when you've layered independent things on top of it.

Hold onto this, because it's the seed of something important: head-of-line blocking is a big part of why the industry went back to UDP to build a faster web — a story we'll pick up shortly.

When Fresh Beats Complete

Here's the mental shift that separates people who really get transport protocols from people who just memorized "TCP reliable, UDP fast." For a huge and growing class of applications, getting the data complete is worth less than getting it fresh — and for those, TCP's greatest strength becomes a liability.

Think about a live video call. A packet carrying a slice of video from 200 milliseconds ago goes missing. TCP would dutifully stop everything and retransmit it — and then proudly deliver you a frame from the past, while the call freezes waiting. But you don't want that old frame; the conversation has moved on. What you want is to skip it and show the next, current frame. A brief glitch is far better than a freeze. This is UDP's world: lose the packet, don't look back, stay live. The same logic drives:

  • Voice over IP — a tiny audio dropout beats a laggy, delayed call.
  • Online games — a player-position update from 100 milliseconds ago is worthless; by the time TCP resent it, three newer positions already came and went. Fire the latest state over UDP and never look back.
  • Live streaming — briefly drop quality or a frame rather than stall the whole broadcast.

And there's a quieter, classic UDP user: DNS, the internet's phonebook (your very next lesson). A DNS lookup is one small question and one small answer. Setting up and tearing down a whole TCP connection with its handshake round-trip, just for that, would double the cost of a lookup that happens billions of times a second. So DNS fires a single UDP datagram and, if no answer comes back, simply asks again. The reliability lives in the application, not the transport — exactly the "build only what you need on the fast pipe" philosophy UDP is built for.

Choosing — and the UDP Comeback

So how do you actually choose? You don't memorize a table; you ask a short chain of questions about this workload:

  • Must every byte arrive intact and in order? (a file, a payment, an API call, a web page, an email) → TCP. Pay the reliability bill; it's worth it.
  • Is fresh data worth more than complete data — is latency the thing you can't sacrifice? (live video/voice, games, real-time telemetry) → UDP, and add back only the reliability you truly need.
  • Is it one tiny request-and-reply where a connection would be pure overhead? (DNS) → UDP.

Get this wrong in either direction and you pay: choose UDP for a file transfer and you'll reinvent TCP, badly, bolting on retransmission and ordering by hand (there's an old warning that those who don't understand TCP are condemned to reimplement it, poorly). Choose TCP for a fast-twitch game and you'll fight its handshakes and head-of-line stalls forever.

Which raises a beautiful question: what if you want both — UDP's speed and reliability, but without TCP's whole-connection head-of-line blocking? That's precisely what the modern web did. QUIC — the protocol under HTTP/3 — is built on top of UDP, and rebuilds reliability, ordering, and congestion control in software, but per independent stream, so a lost packet only stalls its own stream instead of everything. It also folds in encryption to shrink the handshake to as little as zero or one round-trip. It's already carrying roughly a third of web traffic. The punchline for now: UDP was never the loser of this story. It's the blank canvas the fastest web protocol needed — and we'll paint the rest of that picture two lessons from now.

Who uses which, and the UDP comeback. TCP, where everything must arrive: web, email, databases, SSH, file transfer. UDP, where fresh beats complete: DNS, live video, voice, games, QUIC. The comeback: HTTP/3 = QUIC over UDP, rebuilding reliability per-stream to beat TCP's head-of-line blocking. Match the protocol to whether the workload needs every byte or the freshest byte.

The Trade-off

Strip everything down and TCP versus UDP is one clean trade-off, the same shape as every other decision in this course:

Reliability and order, or latency and low overhead. You don't get both for free — you choose which bill to pay.**

You want…Reach for…And you pay in…
every byte, in order, guaranteedTCPround-trips (handshake, ACKs) · header bytes · stalls (HoL)
lowest latency, freshest dataUDPyou build any reliability you need — or do without
a one-shot tiny requestUDPoccasional loss (just ask again)
both, for the modern webQUIC/HTTP-3complexity (reliability rebuilt in user space, over UDP)

Notice what this is not: it is not "TCP good, UDP bad," or "reliable beats unreliable." A guarantee that arrives too late is a cost with no benefit — the retransmitted video frame, the stale game position. And a fast pipe with no guarantees is a disaster for a bank transfer. The skill isn't picking the "better" protocol; it's reading your workload — complete or fresh? bulk or real-time? correctness or latency? — and paying the matching bill on purpose. That judgment is the whole lesson, and it's exactly what you just practiced by flipping the workload switch.

The TCP vs UDP trade-off as a versus card. Setup: TCP needs a handshake costing one round trip, UDP is none and instant. On loss: TCP retransmits, UDP data is gone. Order: TCP guaranteed, UDP as it arrives. Header: TCP ~20 bytes, UDP 8 bytes. Shape: TCP a byte stream, UDP discrete datagrams. TCP is complete and ordered at a price; UDP is instant and lossy for free.

Mental-Model Corrections

"UDP is just a broken, worse TCP." No — it's a different tool. UDP's lack of guarantees is the feature for real-time work: no retransmits means no stale data and no stalls.

"TCP guarantees your data arrives." More precisely: TCP guarantees reliable, in-order, no-duplicate delivery — or it tells you the connection failed. It can't push bytes through a cut cable, and "delivered" means into the receiver's OS buffer, not that your app has processed it.

"UDP is unreliable, so packets are always getting lost." On a healthy network, UDP loss is low. "Unreliable" means no guarantee, not guaranteed loss.

"UDP is always faster." Lower overhead and latency, yes — but for bulk transfer TCP's congestion control gives excellent throughput, and UDP with no congestion control can collapse a network. "Faster" is only true for the latency-sensitive case.

"TCP sends one packet per message." No — TCP is a byte stream with no message boundaries; you must frame messages yourself. UDP is the one that preserves message (datagram) boundaries.

"The handshake is the only cost." Setup RTT hurts short connections, but ongoing costs matter too: ACKs, head-of-line stalls, congestion-control ramp-up. Guarantees cost throughout, not just at the start.

"Just use UDP and add the reliability you need." Only if you truly must — you'll otherwise reinvent TCP, worse. Build on UDP when you need something TCP structurally can't give (per-stream independence, 0-RTT) — which is exactly why QUIC exists.

Try It Yourself: Feel the Handshake and the Loss

Fifteen minutes at a terminal and on a video call will make this permanent. Predict first: on a shaky Wi-Fi connection, which will you notice more — a file download slowing down, or a video call glitching? Why?

  1. Watch the handshake. Run curl -v https://example.com and read the first lines. See Trying… / Connected before any content — that's TCP's connection (and the TLS handshake) completing its round-trips before a single byte of the page arrives. On a far-away or slow link, that pause is the guarantees being paid for.
  2. See the connection state. Run netstat -an (or ss -tan on Linux) while a page loads and spot the TCP states — ESTABLISHED, TIME_WAIT. That's the connection state TCP keeps on both ends (and that UDP never does — remember the 10k-connections problem from earlier).
  3. Feel fresh-beats-complete. Get on a video call over deliberately bad Wi-Fi and watch it glitch and keep going — that's UDP dropping frames to stay live. Then download a large file on the same connection and watch it slow down but finish intact — that's TCP refusing to lose a byte. You're watching the two philosophies you just learned, live, on the same network.

That contrast — the call that degrades to stay current versus the download that waits to stay complete — is the lesson. Once you've felt it, you'll never again have to think hard about which transport a new system should use.

Recap & What’s Next

The Layer-4 choice, and the one rule that drives it:

  • The network is best-effort — packets are lost, reordered, duplicated. Transport (Layer 4) decides what to do about it, and offers two philosophies.
  • TCP = a reliable, ordered byte stream: connection handshake, acknowledgments and retransmission, in-order delivery, flow and congestion control. Everything must arrive → TCP.
  • UDP = a fast, bare, best-effort pipe: no handshake, no reliability, no ordering, an 8-byte header, message boundaries preserved. Fresh beats complete (video, voice, games, DNS) → UDP, plus only the reliability you build yourself.
  • Guarantees cost round-trips — the handshake, the ACKs, the in-order stalls (head-of-line blocking), the cautious ramp. UDP refuses to pay and hands you a blank fast pipe.
  • The choice isn't good-vs-bad; it's complete-vs-fresh, bulk-vs-real-time — pay the matching bill. And QUIC/HTTP-3 proves UDP wasn't the loser: it rebuilds reliability per stream on UDP to beat TCP's head-of-line blocking.

You now know how bytes get somewhere (addressing) and how they get there reliably — or fast (transport). But every connection you've drawn so far started with an IP address you somehow already knew. In real life you type google.com, not 142.250.72.14. So how does a human-friendly name turn into an address the network can route to — billions of times a second, in a few milliseconds, cached at every step? That's the internet's phonebook, and it's next: DNS.