4.3.26 · D2Computer Networks

Visual walkthrough — HTTP - 3 — QUIC, UDP-based, why

2,099 words10 min readBack to topic

We will chase two questions to their picture-proofs:

  1. How many round-trips of waiting before the first useful byte? (setup latency)
  2. When one packet is lost, how many web objects freeze? (head-of-line blocking)

Before a single formula, let us agree on the one measurement everything depends on.


Step 1 — What is a round-trip, and why measure in RTT?

WHAT we do here: we pick as our unit of time instead of milliseconds.

WHY this tool and not raw milliseconds: every step of setting up a connection is a question sent, answer awaited. You cannot proceed until the answer returns — that is exactly one round-trip of waiting. So "how slow is setup" is really "how many round-trips must I wait", and is the natural ruler. Counting in makes the comparison independent of whether you are on fast fibre or slow mobile.

PICTURE: the arrow leaves you, reaches the server, comes back. The full loop is one . Anything you must wait for costs at least one of these loops.


Step 2 — TCP's setup: counting the loops (the "before" picture)

WHAT we do: count for the old stack — TCP first, then TLS 1.3 on top.

WHY two separate counts: in the old world these are two independent conversations stacked on each other. TCP must finish proving the pipe is open before TLS is even allowed to start proving who you are. Two conversations, each needing its own round-trip, means we simply add their loop-counts.

PICTURE: two coloured brackets stacked vertically. The lavender bracket is TCP's handshake — SYN out, SYN-ACK back — that is loop. Only after it closes does the coral bracket (TLS) begin — ClientHello out, ServerHello back — another loop. First request byte can only go after both brackets close.


Step 3 — QUIC's setup: folding the loops into one

WHAT we do: UDP needs no handshake (it is connectionless), so QUIC has nothing to wait for at the transport layer. QUIC then carries the crypto handshake inside its very first flight of packets.

WHY this collapses : the two questions from Step 2 — "is the pipe open?" and "who are you + keys?" — are merged into one question sent in the same first packet. One question, one loop back. That is . There is no separate transport round-trip to wait through, because UDP just fires packets with no permission needed.

PICTURE: one single bracket. Your first packet already contains the crypto ClientHello and the transport parameters together. The server answers once; you are done in one loop. Compare the two-bracket tower of Step 2 to this single bracket.


Step 4 — The degenerate case: 0-RTT for returning visitors

WHAT we do: handle the special input "you have talked to this server before."

WHY it deserves its own step: Steps 2–3 assumed a fresh stranger. But a returning visitor already remembers the keys from last time. So there is no identity/key question to ask at all — you can attach your actual HTTP request to the first packet and send it immediately, before any answer comes back.

PICTURE: the request rides on the outgoing arrow itself — no bracket, no waiting loop before data. The server sees your request and the resumption ticket in the same breath. This is the edge case.


Step 5 — The second race: what one lost packet costs

Now we switch questions entirely: forget setup, assume the connection is up. We are loading a page with many objects and one packet is lost. How many objects freeze?

WHAT we do: line up objects and knock out the packet of exactly one of them.

WHY ordering is the villain: TCP promises "no byte handed up until every earlier byte arrived." That promise is a global line. QUIC promises the same, but only within each stream — a per-stream line.

PICTURE: boxes labelled object 1…N. The lost packet is marked with a coral ✗. We are about to see how far the freeze spreads in each world.


Step 6 — TCP's blocking: the whole line freezes behind the gap

WHAT we do: in the single TCP stream, mark the lost packet, then shade everything after it that cannot be delivered.

WHY everything after freezes: TCP will not hand object to the browser until the missing packet of object is retransmitted — even though those later bytes have already physically arrived. The in-order rule holds them hostage. That is head-of-line blocking at the transport layer, and HTTP/2 could not escape it because it multiplexed everything onto one TCP stream.

PICTURE: the ✗ sits at position ; a coral wash covers positions through . All those objects wait for one retransmission (which itself costs ).


Step 7 — QUIC's blocking: only the injured stream freezes

WHAT we do: same loss, but now each object is on its own stream.

WHY the freeze can't spread: QUIC's in-order rule is per stream. Object has its own private line, so its missing packet holds up only object . Streams have their own independent ordering and keep flowing — this is exactly why transport-level HOL blocking disappears.

PICTURE: the ✗ still hits one box, but now only that single box is coral-washed. All the other boxes stay mint-green and delivered. Contrast this directly with Step 6's coral flood.


Step 8 — Why not a brand-new protocol? (the constraint that forced UDP)

WHAT we do: justify why the carrier is UDP rather than a shiny new transport at the IP layer.

WHY this is a derivation step and not trivia: the whole "independent streams + user-space transport" design is only deployable because middleboxes (routers, firewalls, NATs) drop packets carrying an unknown IP protocol number. UDP is already waved through everywhere (it carries DNS). So QUIC must ride inside UDP as its delivery truck, and rebuild reliability/ordering/congestion control itself, encrypted, in user space.

PICTURE: three lanes reach a firewall gate. The "new protocol" lane is blocked (✗). The TCP lane is allowed but frozen/ossified. The UDP lane passes freely (✓) carrying the QUIC truck.


The one-picture summary

This single figure compresses both derivations: the setup ladder () on the left, and the blocking spread ( vs ) on the right.

Recall Feynman: the whole walkthrough in plain words

First we agreed to measure waiting in "round-trips" — a loop out to the server and back — because every setup question is ask, then wait for the echo. The old way asks two questions in a row: "is the line open?" (one loop) then "who are you and what's the key?" (another loop) — two loops of waiting. QUIC squishes those into one packet, so one loop; and if you've visited before, it remembers the key and sends your request instantly — zero loops.

Then a different story: many toys travelling on one road. The old TCP rule is "unload strictly in order," so if toy number 25 falls off, toys 26 through 50 all wait too — half the pile freezes. QUIC gives every toy its own little go-kart with its own ordering, so a broken go-kart stops only that one toy; the other 49 sail through. And all of this rides on the ordinary UDP road because the fancy special roads get blocked by the guards (middleboxes) — the plain road is the only one that's always open.


Connections

  • 4.3.26 HTTP - 3 — QUIC, UDP-based, why (Hinglish)
  • TCP — three-way handshake and reliability
  • UDP — connectionless transport
  • TLS 1.3 — handshake and 0-RTT
  • HTTP-2 — multiplexing and HPACK
  • Head-of-line blocking
  • Congestion control — slow start, AIMD
  • Middlebox ossification and protocol evolution