Edited by humans. Written by AI. How our editing works
All articles

TCP vs UDP: Why Protocol Choice Shapes Game Quality

TCP's ordering guarantee is perfect for files—and a liability for live games. Here's what happens when a packet dies and why your protocol choice is an invisible design decision.

Mike Wierzbicki

Written by AI. Mike Wierzbicki

August 28, 20268 min read
Share:
Bearded man pointing at head against blue background with "TCP vs UDP" comparison graphic showing reliability and speed…

Photo: AI. Astrid Lehmann

Pick the wrong transport protocol for a live-service multiplayer game and you will spend your post-launch months debugging player complaints that read like ghost stories: enemies teleporting, hit registration that feels broken, rubber-banding that only shows up under real-world network conditions that your office LAN never produced. You will run those bugs through QA that cannot reproduce them, and eventually someone will schedule a crunch sprint to chase a problem that was baked into the networking layer before the first line of game logic was ever written. Protocol choice is not an infrastructure detail you revisit later. It is a design decision that ships with the game.

That's the practical context for a recent Dave's Garage video that walks through what actually happens when you delete a single packet in transit and let Wireshark show you the consequences under each protocol. The experiment is simple enough to be reproducible on a weekend. What it reveals is not.

The Deleted Packet

Dave sets up two machines and deliberately kills one packet mid-stream—packet five out of ten—then runs the same test under UDP and TCP. The UDP result is exactly what the protocol promises and nothing more: packets one through four arrive, five vanishes, six through ten arrive. The receiving application gets nine out of ten messages and continues without ceremony. No error signal, no pause, no recovery attempt. The gap is permanent, and the stream moves on.

The TCP result is where the engineering trade-off becomes visible. Packets six through ten reach the receiving machine. They clear the network card. They sit in kernel memory. The application does not see any of them. TCP is holding them hostage until packet five can be recovered.

"TCP promises the application an ordered stream of bytes," Dave explains in the video. "If byte number 50,000 is missing, TCP cannot simply hand over byte 51,000 and hope that nobody notices. Doing so would violate the abstraction that it has promised, so it waits."

That waiting—head-of-line blocking—is not a bug in TCP. It is the exact behavior TCP is designed to produce. The protocol's entire value proposition is that it turns a packet network, which is inherently unreliable, into something that looks to applications like a clean, ordered byte stream. Spiceworks describes the mechanism clearly: TCP identifies the lost packet and retransmits it; UDP has no mechanism to detect loss at all, let alone recover from it. That distinction is accurate but incomplete. What it leaves out is that TCP's recovery process has a cost that varies with network conditions, and in real-time applications that cost can arrive at exactly the wrong moment.

What Stale Data Costs in a Shipped Game

The voice call example Dave uses is clean: a lost audio fragment gets reconstructed and delivered, but by then the conversation has already moved forward, and you have a technically correct reconstruction of something nobody needs anymore.

The gaming version is messier, and the pattern is familiar to anyone who has shipped a multiplayer title. A game server sends position updates at regular intervals—call them ticks. Player position at tick 100, then 103, then 107. The packet carrying tick 103 disappears. Under TCP, the client freezes the remote player at their tick-100 position and waits. Tick 107 is already sitting in the client's receive buffer. The client knows something newer exists. TCP does not care. The contract says ordered delivery, and ordered delivery is what the application gets—which means the client renders a player standing still in a location they left several ticks ago until the retransmit cycle closes the gap.

That frozen ghost is not a rendering bug or a physics issue. It is the TCP ordering guarantee functioning exactly as designed, applied to data where ordering matters far less than freshness. As Dave puts it: "stale data can be worse than missing data." In the position-update case, you do not need tick 103 once tick 107 has arrived. You already know something newer. The correct move is to throw the gap away and render what you have.

This is why mature multiplayer netcode for fast-paced games almost universally runs game state updates over UDP, implementing their own application-layer logic for the small subset of messages—player actions, hit confirmations, authoritative state corrections—that genuinely cannot be dropped. GeeksforGeeks notes the use-case split directly: TCP for reliability-critical transfers, UDP for applications where low latency outweighs guaranteed delivery. The pattern has been established long enough that choosing TCP for game state updates is not a neutral default. It is a decision, and when it surfaces in post-launch debugging, it tends to surface as a mystery rather than a protocol choice.

What Each Protocol Actually Is

The header size alone signals the design philosophy. UDP's header is eight bytes: source port, destination port, length, checksum. That is the complete list. No sequence numbers, no acknowledgements, no flow control, no retransmission logic. Each UDP datagram is a self-contained message. The network delivers it or it does not arrive. UDP offers no opinion on which outcome occurred.

TCP thinks in bytes, not packets. Every byte in a connection occupies a numbered position in a continuous stream, and acknowledgements track exactly where the receiver has confirmed coverage. When a segment goes missing, the receiver's acknowledgement number freezes at the gap. Later segments keep arriving and keep getting buffered, but the ACK number does not advance—a pattern that is visible in Wireshark and tells you everything about where a slow connection actually stopped making progress. TCP's congestion control then responds to that loss signal by pulling back its transmission rate, which means a single dropped segment on a high-bandwidth path can cost more than just the retransmit. It can trigger a sustained reduction in throughput while the sender cautiously rebuilds.

UDP preserves one additional property that matters for application design: message boundaries. Two UDP sends of distinct payloads arrive as two distinct messages. TCP makes no such guarantee—two sends may arrive concatenated, split, or interleaved with other data. Applications using TCP for anything beyond a raw byte stream need to implement their own message framing, which is additional complexity that UDP-based code avoids.

QUIC: Choosing Which Data Gets to Block

The newest layer on this stack is QUIC, the transport underneath HTTP/3, which runs over UDP. Dave's explanation of why is worth quoting in full: "QUIC does not make packet loss disappear, it changes what must wait for what."

HTTP/2 improved on its predecessor by multiplexing many logical streams over a single TCP connection, avoiding the overhead of opening dozens of separate connections. The problem is that underneath all those streams there is still one TCP byte stream. A lost packet in one stream holds up all the others. Head-of-line blocking applies to the entire connection.

QUIC implements its own reliability, acknowledgements, retransmission, congestion control, and encryption above UDP. But because it manages its own stream multiplexing, a lost packet on one stream does not block delivery on unrelated streams. The protocol gets to decide, at the application level, which missing data is allowed to halt which other data. That is the freedom that building above UDP provides—not the elimination of reliability, but control over the scope of what reliability covers.

The three-way comparison Dave frames it as: TCP promises every byte in order; UDP promises only the datagrams that actually arrive; QUIC promises reliability, but reserves the right to vote on which missing data is allowed to stop everything else.

The Default That Costs You Later

The game industry tends to learn networking lessons the hard way, after launch, under production load, from player complaints submitted by people who do not know what head-of-line blocking is but can describe exactly what it looks like on screen. The pattern repeats often enough that it is less a surprise than a tax—paid in post-launch crunch, in debugging sessions that trace back to architectural choices made early in development when TCP was the default because it was familiar, because the documentation said it was reliable, because nobody stopped to ask what "reliable" means for a 64-player match where every tick contains data that will be irrelevant by the time it is retransmitted.

TCP is an extraordinary engineering achievement for the problem it is designed to solve. It turns an unreliable network into something that looks like a guaranteed byte stream, and that guarantee is exactly right for file transfers, database transactions, SSH sessions, anything where a missing byte is worse than a slow byte. But the word "reliable" is doing a lot of work in that sentence, and it is not self-evident. Reliable for what? Reliable compared to what alternative cost?

Most studios know the answer. The ones that ship network code without asking the question find out anyway.


Mike Wierzbicki covers game development and industry labor for Buzzrag.

More Like This

RAG·vector embedding

2026-08-28
1,926 tokens1536-dimmodel text-embedding-3-small

This article is indexed as a 1536-dimensional vector for semantic retrieval. Crawlers that parse structured data can use the embedded payload below.