Sending Independent Datagrams

Opening Question

What is the simplest useful service the transport layer can provide?

Real-World Story

Mailing a postcard is about as simple as sending something gets. You write a short message, address it, drop it in a mailbox, and you’re done. The postal service doesn’t ask you to establish an ongoing relationship with the recipient first, doesn’t promise you the postcard will actually arrive, doesn’t tell you if it gets lost, and doesn’t offer to send a replacement if it does. Each postcard is entirely independent of every other one you might send the same person — there’s no shared “conversation” the postal service is tracking between you and them, just individual pieces of mail, each handled on its own.

For a huge number of everyday messages, this is not a shortcoming — it’s exactly the right amount of service. A birthday postcard that arrives isn’t devalued by not having a delivery receipt. And if you’re sending a fast sequence of them, and one goes missing, there’s usually no need for the postal service to notice and resend it on your behalf; you’ll either notice yourself or, often, it simply won’t matter.

Worked Example

Consider three very different pieces of data crossing a network at nearly the same moment: a DNS query asking for a website’s IP address, a multiplayer game sending a player’s current position, and a temperature sensor reporting its latest reading.

The DNS query is small, and if the answer doesn’t arrive in a reasonable time, the asking application can simply try again — there’s no benefit to the network itself guaranteeing delivery of that specific request, since a fresh retry is just as good as a guaranteed original.

The game’s position update is even less interested in guarantees: if this exact update is lost, but the next one — sent a fraction of a second later, describing where the player is now — arrives fine, resending the lost, now-outdated update would be actively counterproductive. The game doesn’t want an old position delivered late; it wants the freshest position delivered promptly, and stale data delivered “reliably” is often worse than no data at all.

The sensor reading behaves similarly: a reading from two seconds ago that arrives after three retries and a long delay is frequently less useful than simply waiting for the next fresh reading, due any moment anyway.

In all three cases, the natural unit is one self-contained message, sent independently, with no requirement that the network track a running conversation or guarantee eventual delivery. What all three need from the transport layer is exactly a postcard service: fast, simple, message-at-a-time, with no obligations beyond a genuine best-effort attempt.

Core Intuition

Not every application wants — or benefits from — a heavyweight, guaranteed, ordered delivery service. Some data is only valuable if it’s fresh, some errors are cheaper to simply retry than to have the network resolve automatically, and forcing every single exchange through a guaranteed, ordered channel would add cost and delay that plenty of applications neither need nor want. UDP exists to be the minimal, honest option: send this one message, now, with no promises beyond a genuine attempt.

Technical Explanation

UDP (User Datagram Protocol) is a transport-layer protocol that sends a datagram — one self-contained unit of data, addressed with source and destination ports (Ch. 12) — as an independent, one-shot message. There is no setup phase before the first datagram can be sent, no teardown after the last one, and no ongoing state linking one datagram to the next beyond whatever the application chooses to track on its own. This is what it means to call UDP connectionless: the transport layer itself maintains no notion of an ongoing conversation between two endpoints, only individual, self-contained sends.

Critically, UDP preserves the message boundary the application gave it: if an application hands UDP a 200-byte message, the receiving application gets exactly that 200-byte message back, as one unit, with the boundary intact — not merged with the message before it, not split across two deliveries. This is a genuinely different contract from the byte-stream model that TCP will introduce in the next chapter, and it’s precisely what makes UDP a natural fit for applications like DNS or game-state updates, where “this specific message, whole and separate” is exactly what the application wants.

UDP does include a checksum — a value computed over the datagram’s contents that lets the receiver detect certain kinds of corruption in transit. It’s worth being precise about what this buys you: a checksum only detects that something went wrong; a corrupted datagram that fails the check is simply dropped, not repaired and not automatically retried by UDP itself. Detection is not the same service as recovery.

That last point generalizes: everything that UDP does not do — retransmitting a lost datagram, reordering datagrams that arrived out of sequence, pacing how fast datagrams are sent to avoid overwhelming the receiver or the network — is left entirely to whichever application sits on top of UDP, if that application needs it at all. This is application-managed reliability: rather than the transport layer imposing one reliability model on every use case, UDP hands the decision back to the application, which is often in a far better position to know whether reliability is worth the cost for its particular kind of data. A game, for instance, might implement its own light retry logic for critical state changes while deliberately not bothering for routine position updates. DNS, similarly, handles its own retries at the application layer (and, when a reply won’t fit in one datagram, falls back to TCP rather than asking UDP to somehow provide reliability it was never built to offer).

Packet-Journey Checkpoint

Before the café laptop’s browser ever opens a connection to fetch example.net’s page, it typically needs to resolve example.net’s hostname into an IP address. That initial DNS query is a natural UDP exchange: one small request, one small (usually) reply, no ongoing conversation needed, and if the first attempt is lost, the resolver simply tries again. The main HTTPS page fetch that follows is a different story — that one does need ordering and reliability, which is exactly why it won’t use UDP alone, as the next two chapters will show.

Common Misconceptions

UDP is inherently faster in every application.

Why it’s wrong: UDP has less protocol overhead than TCP, but “faster” depends entirely on what the application does with (or without) reliability on top of it. An application that implements its own careful retry and ordering logic over UDP may end up no faster, and sometimes slower, than simply using TCP’s already-built mechanisms.

Correct intuition: UDP is lighter-weight and lower-latency for the transport layer’s own overhead, but real end-to-end speed depends on the whole system, not the transport protocol alone.

Analogy: A postcard is dispatched quickly, but if you then have to phone the recipient to confirm it arrived and resend it yourself when it doesn’t, the total time may not beat a tracked parcel that just handles this automatically.

UDP traffic cannot be reliable.

Why it’s wrong: UDP itself provides no reliability, but nothing stops an application built on UDP from implementing its own retransmission, acknowledgment, or ordering scheme. QUIC (Ch. 24) is a major real-world example of a reliable protocol built on top of UDP.

Correct intuition: “UDP” describes the transport layer’s own minimal contract, not a ceiling on what the full application-plus-transport system can achieve.

Analogy: The postal service doesn’t track your postcards, but you’re free to number them yourself and ask the recipient to confirm receipt — the reliability just comes from you, not the mail carrier.

Connectionless means no state exists anywhere.

Why it’s wrong: “Connectionless” describes UDP’s own transport-layer behavior — it maintains no ongoing session state. It says nothing about the application layer, which is often tracking plenty of its own state (a DNS resolver’s pending queries, a game’s session state) independently of UDP.

Correct intuition: UDP not tracking a conversation doesn’t mean nobody is; it just means that job, if needed, belongs to the application.

Analogy: The postal service keeps no file on your correspondence with a specific friend — but you might.

UDP preserves delivery order.

Why it’s wrong: UDP datagrams are independent, and the underlying IP layer (Ch. 9-10) may deliver them along different paths at different times; nothing in UDP itself reorders datagrams that arrive out of sequence.

Correct intuition: If an application needs its data in order, it either needs its own ordering logic or a transport protocol (like TCP) that provides ordering itself.

Analogy: Postcards mailed on consecutive days aren’t guaranteed to arrive in the order they were sent.

Using UDP avoids congestion concerns.

Why it’s wrong: UDP has no built-in congestion control (Ch. 15), which means an application sending UDP traffic aggressively can contribute to network congestion without any automatic mechanism reining it in — this is a real risk, not an advantage.

Correct intuition: The absence of congestion control is a responsibility shifted to the application, not a problem that’s been solved by simply not using TCP.

Analogy: A courier company with no traffic-awareness at all can flood the roads just as easily as one that’s supposed to be tracking congestion — arguably more easily, since nothing is watching.

Practical Implications

When evaluating why a protocol was built on UDP instead of TCP — DNS, streaming video, real-time voice and video, QUIC — the answer is almost always about message boundaries, avoiding head-of-line blocking (Ch. 23), or wanting custom reliability/pacing rather than TCP’s fixed byte-stream model, not simply “UDP is faster.” It’s also worth remembering, when debugging, that a UDP-based application failing silently under packet loss is not a network bug — it’s the expected behavior of a protocol that was never asked to guarantee delivery in the first place.

Key Takeaway

UDP preserves application message boundaries while leaving delivery, ordering, pacing, and recovery largely to the application.

What to Remember

  • UDP sends independent datagrams with no connection setup, teardown, or ongoing session state at the transport layer.
  • UDP preserves the application’s message boundaries — one send equals one intact receive, not a merged or split stream.
  • UDP’s checksum detects corruption; it does not repair it or trigger automatic retransmission.
  • Reliability, ordering, and pacing are left to the application, which can add exactly as much of each as it actually needs.
  • UDP being connectionless at the transport layer doesn’t mean the application above it is stateless.
  • Applications choose UDP for message-boundary-preserving, low-overhead, freshness-over-completeness use cases — not simply because it’s “faster.”

The Next Obvious Question

What if an application needs all the data, in order, despite loss?