Skip to main content
Back to blog

TCP vs UDP: What Happens to a Packet That Goes Missing

Technical

TCP vs UDP: What Happens to a Packet That Goes Missing article illustration

Your browser, your video call and your name lookups all travel over the same addresses and the same routers. What differs is the thin layer wrapped around each one, and the difference becomes visible in a single situation: a packet that never turns up.

Both sit on top of IP, and both add a port number

IP gets a packet to a machine. It does not know which program on that machine is waiting for it, and it makes no promise that the packet will arrive at all. TCP and UDP are the two layers that sit above it, and they fill that gap in opposite ways.

Both start with the same thing, a port number, so the operating system knows which program should receive what turns up. What makes a port open covers the numbering, and the difference between open, closed and filtered. The part worth carrying into this article is that the two protocols keep separate port spaces. TCP 443 and UDP 443 are different doors wearing the same number, and a program listening at one of them hears nothing at the other.

After that they go in opposite directions.

UDP does almost nothing, and says so

RFC 768, the User Datagram Protocol, was published in August 1980 and runs to three pages. Its introduction states the ambition plainly: it gives application programs a way to send messages to other programs “with a minimum of protocol mechanism”.

The header is four fields. Source port, destination port, length, checksum. That is all of it. There is no connection to establish, no record of what was sent and no numbering, so neither end knows whether anything went astray.

The specification is candid about the cost. It describes the protocol as transaction oriented and states that “delivery and duplicate protection are not guaranteed”. Datagrams can vanish, and they can arrive twice, and UDP will not mention either.

It then names its own replacement: “Applications requiring ordered reliable delivery of streams of data should use the Transmission Control Protocol (TCP)”.

TCP promises the whole stream, in order

TCP is that other answer. Its current specification is RFC 9293, which became Internet Standard 7 in August 2022, replacing the 1981 document that had defined the protocol for four decades.

The summary of what it offers fits in one sentence: “TCP provides a reliable, in-order, byte-stream service to applications.”

Reliability has a mechanism behind it, and the same section names it: “TCP reliability consists of detecting packet losses (via sequence numbers) and errors (via per-segment checksums), as well as correction via retransmission.” Every byte carries a number, the receiver confirms which numbers it holds, and anything unconfirmed is sent again.

The connection comes first, and its purpose is not the obvious one. Before any data moves, the two ends exchange the sequence numbers they intend to start from. RFC 9293 gives the reason for doing that in three messages rather than two, and the reason is defensive: “The principal reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion.” The handshake is less an introduction than a check that the conversation is the current one.

The guarantee is paid for in waiting

This is where your missing packet ends up.

If the service is in-order, a gap has to be filled before anything behind it can be handed over. Bytes that arrived perfectly well sit in the receiver’s buffer, complete and unusable, until the missing piece has been sent again and dropped into place. The application sees nothing new during that pause, then receives everything at once.

For a file, a web page or an email, that is the right trade. The pause is invisible and a corrupted result would not be. For anything live it is the wrong trade, because a retransmitted fragment of speech arrives after the moment it belonged to. A small gap now beats perfect audio a second late.

It also explains why loss on a TCP transfer shows up as slowness rather than as damage. The drop is a signal the sender is built to act on, and what a packet loss figure is really telling you covers why that happens under load, and what the sender makes of it.

Where each one turns up

RFC 768 handed down the sorting rule itself, back when there was only one other option: if you need ordered, reliable delivery of a stream, use TCP. Everything else is a candidate for UDP.

UDP suits the brief exchanges and the live ones. RFC 768 named the Internet Name Server as one of its two major uses back in 1980, and name resolution still works that way: one question, one answer, and how a DNS lookup is answered shows a sequence that gains nothing from a handshake it would use once and discard. The live case follows from the section before this one, where arriving late is worse than not arriving at all.

UDP also carries tunnels. WireGuard runs over UDP and declines TCP outright, which the comparison of VPN protocols records in the project’s own words. The reason is this article’s subject applied twice over. Put a retransmitting protocol inside another retransmitting protocol and both layers respond to the same loss, each running its own timer across the same bytes, with the outer one already repairing what the inner one has just decided to repair again.

TCP suits whatever has to arrive whole. A page with a chunk missing, a half-delivered email or a file with a hole in it would each be worse than a pause, and the pause is what the guarantee costs.

An application can build its own waiting

The split is less fixed than it looks, because nothing stops a program taking UDP and adding back only the parts it wants.

That is what QUIC does. RFC 9000 carries the arrangement in its own title, QUIC: A UDP-Based Multiplexed and Secure Transport, and it describes rebuilding what UDP leaves out: QUIC “provides the necessary feedback to implement reliable delivery and congestion control”.

What changes is where the ordering lives. One QUIC connection carries several streams, and the specification calls a stream “an ordered byte-stream abstraction”, so order is kept inside each stream rather than across the connection as a whole. Data waits behind a gap in its own stream and not behind a gap in somebody else’s.

So this is not a contest with a winner in it. TCP hands you reliability whether the job needs it or not. UDP hands you an empty space, and what goes into it is the application’s decision.

What this means when you test a port

Our port checker asks one of our servers to make a TCP connection inbound to the public address your browser is using, so it reports on TCP ports and nothing else.

That is a property of the protocols rather than a shortcoming in the tool. A TCP port either completes a handshake or refuses one, so there is an answer to collect either way. A UDP port has no handshake to complete. A datagram arrives, and whether anything comes back is the receiving program’s decision, because UDP itself has nothing of its own to say. A prober that does not speak the application’s own protocol has nothing to trigger a reply with, so an open UDP port and a filtered one can look identical from outside. That leaves running the game or the tunnel itself and watching whether it works.

The address under test does not change between the two. The address a site sees for you is read from the IP header, which both protocols sit inside, so it stays the same whichever one is carrying your traffic.

None of this is a setting you can go and change. It belongs to whoever wrote the software you are using, and they made the call long before you opened it. It is still worth knowing, because it ties together symptoms that otherwise look unrelated: why a video call degrades into small gaps instead of freezing, why a download stalls and then picks up again, and why a forwarded UDP port is harder to confirm than a TCP one. TCP stops and waits for the missing packet. UDP does not, and leaves that decision to whatever is built on top of it.