Why can TCP's reliable, in-order delivery make a voice call or a fast-paced multiplayer game worse than UDP when packets are lost?
answer
- one missing piece holds the line
- data already arrived but cannot be read
- three duplicate ACKs or a timeout
- newest data beats all data
basics
~20 sTCP releases bytes only in order, so one lost segment stalls all later data until its retransmission arrives, a round trip or more. Voice and game updates are stale by then; UDP lets the application skip or conceal the loss instead.
solid answer
~40 sTCP hands the application a byte stream strictly in order. If one segment is lost, later segments that have already arrived sit in the receive buffer until the retransmission lands: transport head-of-line blocking. Recovery takes about a round trip after three duplicate ACKs trigger fast retransmit (RFC 5681), or a retransmission timeout if too few segments follow the loss; RFC 6298 says a timeout computed below 1 second SHOULD be rounded up to 1 second. The application sees a stall, then a burst of old data. A voice packet that misses its playout time is discarded anyway, and a game snapshot is superseded by the next one. Over UDP, each datagram is delivered on arrival, so the application drops stale state, conceals lost audio, and makes only the messages that matter reliable.
go deeper
Recall that TCP delivers in order, so one lost packet delays everything behind it, and that real-time apps prefer to skip late data.
Walk through a lost segment: buffered later data, duplicate ACKs, fast retransmit, then a burst. Explain why that burst is useless to voice and games.
Discuss sparse streams where only the retransmission timeout can recover, and how a UDP design mixes unreliable state with a small reliable channel.
Frame the per-message reliability policy as a product decision: which game events or media signals justify reliable delivery, and what latency budget each consumes.
## Head-of-line blocking at the transport layer TCP gives the application a **byte stream delivered in order**. A TCP receiver may accept segments that arrive out of order and keep them in its buffer, but it cannot hand any byte to the application until every earlier byte has arrived. When one segment is lost, the data behind it waits, even though it is already sitting on the receiving host. This is **transport head-of-line (HOL) blocking**: the first missing piece holds up the whole line. A worked trace, with a hypothetical round-trip time of 100 ms: 1. The sender transmits ten small segments, one game-state update each. 2. Segment 4 is lost; segments 5 to 10 arrive and are buffered. 3. Each arrival after the gap produces a duplicate ACK. On the third duplicate ACK, the sender performs **fast retransmit** (RFC 5681). 4. The retransmitted segment 4 arrives roughly one round trip after the loss was detected. 5. Only then are updates 4 to 10 released to the application, all at once. The application sees a stall followed by a burst. For a file download that is invisible. For voice or a game it is exactly the wrong behaviour: the burst contains old news. ## When recovery is slow: sparse streams and the RTO Fast retransmit needs **three duplicate ACKs**, which means at least three later segments must arrive. Real-time streams are often sparse, and a loss near the end of a burst may have too few segments behind it. Then recovery waits for the **retransmission timeout (RTO)**. RFC 6298 says an RTO computed below 1 second SHOULD be rounded up to 1 second, and each repeated timeout backs off exponentially. Some implementations choose a lower floor, and RFC 8985's RACK-TLP sends a tail loss probe to detect such losses sooner, but a stall of hundreds of milliseconds is still realistic. That is longer than a voice call or a fast game can hide. TCP's **congestion control** also lowers the sending rate after a loss, whether the loss came from congestion or from a noisy wireless link. ## Why the late data is worthless - **Voice and video calls.** The receiver plays media out of a short **jitter buffer** that absorbs variation in delay. A packet that arrives after its playout time is discarded anyway, and the decoder conceals the gap. Waiting for it only delays everything behind it. - **Fast-paced games.** Clients send inputs and servers send state snapshots many times a second. Each snapshot supersedes the previous one, so re-delivering one from 100 ms ago is pointless: the next one already describes the present. - **Live video.** A frame that misses its display time is useless to the viewer. The common thread: these applications care about the **newest** data, not **all** of it. ## What UDP gives instead UDP hands each datagram to the application as soon as it arrives, in whatever order, and leaves loss handling to the application. The application then chooses per message: | Message | Treatment over UDP | |---|---| | Position or state snapshot | Unreliable; stale ones discarded by an application sequence number | | Audio or video frame | Unreliable; a loss is concealed at playout | | Chat message, item pickup, match result | Reliable at application level: acknowledged and resent | | Control messages, such as a request for a fresh key frame | Reliable, often sent with priority | Rebuilding **only the reliability each message needs** is the whole point. TCP offers a single all-or-nothing contract for the entire stream; it cannot deliver byte 1,000 while byte 500 is missing. ## Where this leads The same transport-level blocking motivated QUIC (RFC 9000), which runs over UDP so that a loss blocks only the streams whose data was in the lost packet; how its streams work belongs to the HTTP/3 and QUIC topic. How media is framed and timestamped belongs to the RTP topic. ## Common mistakes - Blaming the stall on the network rather than on in-order delivery at the receiver. - Believing that disabling Nagle's algorithm fixes it. Nagle only delays small sends while earlier data is unacknowledged; the receiver still waits for the missing bytes. - Assuming UDP is automatically lower latency. It only is if the application actually drops or conceals late data instead of re-implementing TCP's wait.
- Would disabling Nagle's algorithm with TCP_NODELAY fix the stalls?No. Nagle's algorithm (RFC 896, now described in RFC 9293) makes a sender hold small writes while earlier data is unacknowledged, so disabling it removes a send-side delay. Head-of-line blocking happens at the receiver: bytes after a gap cannot be delivered until the missing segment is retransmitted, whatever the sender's coalescing policy.
- What does a voice application do with an audio packet that arrives after its playout time?It discards it. The receiver plays audio from a short jitter buffer; once a packet's slot has passed, the decoder has already concealed the gap, for example by extending or interpolating neighbouring audio. A larger buffer tolerates more delay variation but adds latency to the whole call, so the design deliberately trades completeness for timeliness.
Live subtitles on a broadcast: if one line is garbled, viewers want the next line on time, not the whole programme paused until the garbled line is re-sent. TCP pauses the programme; UDP lets the application skip the line.
saying these in an interview costs you the question
- TCP delivers segments that arrived after a gap and fills the gap later
- Head-of-line blocking is caused by the network, not by in-order delivery
- Disabling Nagle's algorithm removes TCP head-of-line blocking
- UDP is automatically low-latency even if the application waits for every packet
- A game should retransmit every lost position update to stay accurate