UDP: Connectionless Transport, Message Boundaries, and When to Use It

2 min readSystems & Networking

UDP is a connectionless, message-oriented protocol with an 8-byte header. It provides no delivery guarantees, ordering, or error correction. Applications choose UDP when they need low latency (DNS, gaming), can tolerate loss (video streaming), or implement their own reliability (QUIC). Unlike TCP's byte stream, UDP preserves message boundaries — each send() is received as one datagram.

udpnetworking

UDP header

 0               8              16              24             31
┌───────────────┬───────────────┬───────────────────────────────┐
│  Source Port  │   Dest Port   │            Length             │
├───────────────┴───────────────┼───────────────────────────────┤
│           Checksum            │           Data ...            │
└───────────────────────────────┴───────────────────────────────┘

UDP header: 8 bytes. TCP header: 20+ bytes. The entire UDP overhead is source port (2B), destination port (2B), length (2B), checksum (2B). No sequence numbers, no acknowledgment, no window size, no connection state.

Maximum datagram size: 65,535 bytes (16-bit length field) minus 8-byte header = 65,527 bytes payload. In practice, most datagrams are under 1472 bytes to avoid IP fragmentation over Ethernet (MTU 1500 - 20 IP header - 8 UDP header = 1472).

TCP vs UDP

| Property | TCP | UDP | |---|---|---| | Connection | 3-way handshake required | None | | Delivery | Guaranteed (ACK + retransmit) | Best-effort | | Ordering | Preserved (sequence numbers) | Not guaranteed | | Flow control | Yes (receiver window) | No | | Congestion control | Yes (slow start, CWND) | No | | Message boundaries | No (byte stream) | Yes (each send = one receive) | | Header overhead | 20+ bytes | 8 bytes | | Latency | RTT overhead for connection + ACKs | Send immediately |

The "message boundaries" row is critical: TCP is a byte stream. You write(100) then write(50) and the receiver might get read(150) in one call. UDP delivers each datagram as-is — a sendto(100) produces exactly one recvfrom(100) at the receiver.

UDP sends cannot be split across multiple receives — but IP fragmentation can still occur below UDP

ConceptNetworking

UDP preserves message boundaries at the socket API level: one sendto() call creates one UDP datagram, which arrives as one recvfrom(). However, if the datagram exceeds the path MTU, IP will fragment it into multiple IP packets at the network layer. All fragments must arrive and be reassembled by the destination IP stack before UDP delivers the complete datagram to the application. A single lost fragment causes the entire datagram to be dropped (IP reassembly timeout). This is why UDP-based protocols typically keep datagrams under the path MTU.

Prerequisites

  • TCP/IP model
  • MTU and fragmentation
  • Socket programming

Key Points

  • UDP preserves message boundaries: one send = one receive (at the socket layer).
  • TCP is a byte stream: message boundaries are the application's responsibility.
  • IP fragmentation happens below UDP — large UDP datagrams can be split by IP, but any lost fragment drops the whole datagram.
  • DNS traditionally uses UDP (single request/response fits in one small datagram). Falls back to TCP for responses > 512 bytes.

When applications choose UDP

DNS queries: A DNS request + response fits in a single UDP exchange. No handshake overhead. If the response is lost, the resolver retries. TCP fallback for large responses (DNSSEC, zone transfers).

Real-time media (video/audio): Video conferencing (Zoom, WebRTC) uses UDP. A late video frame is worse than a lost one — retransmitting stale frames would increase latency and buffer more than the loss harms quality. Applications implement their own jitter buffers and loss concealment.

Online games: Player position updates at 60Hz. A missed position update becomes irrelevant 16ms later when the next one arrives. The game applies dead reckoning (extrapolate position) for lost packets. Retransmitting stale positions would cause ghost-like jumps.

QUIC (HTTP/3): QUIC runs over UDP but implements its own reliability, ordering, and TLS. This lets QUIC avoid TCP's head-of-line blocking: in HTTP/2 over TCP, a single lost packet stalls all multiplexed streams. QUIC over UDP handles per-stream loss independently.

📝UDP checksum: optional in IPv4, mandatory in IPv6

The UDP checksum covers the UDP header, data, and a pseudo-header derived from the IP header (source IP, destination IP, protocol, UDP length). This cross-layer check catches packets delivered to the wrong destination due to IP routing errors.

In IPv4, a checksum of 0x0000 means "no checksum" — the sender disabled checksum computation. This is allowed for performance in trusted networks (e.g., within a datacenter over lossless Ethernet). In IPv6, the UDP checksum is mandatory because IPv6 removed the IP header checksum.

For applications that need stronger integrity guarantees (e.g., DTLS, QUIC), application-layer MACs replace or augment the UDP checksum.

An application sends two UDP messages — first 100 bytes, then 50 bytes — to a server. The server calls recvfrom() once. What does it receive?

easy

UDP preserves message boundaries. TCP is a byte stream and does not.

  • A150 bytes — UDP buffers both messages and delivers them together
    Incorrect.UDP doesn't buffer and combine messages. Each sendto() creates a separate datagram. The server receives exactly one datagram per recvfrom() call.
  • B100 bytes — the first message sent
    Correct!UDP preserves message boundaries. The first sendto(100) creates a 100-byte datagram; the second sendto(50) creates a separate 50-byte datagram. The server's first recvfrom() receives exactly the first datagram (100 bytes). The 50-byte datagram stays in the socket receive buffer until the next recvfrom() call. Compare to TCP: if you send 100 then 50 bytes over TCP, the server might receive 150 bytes in one read() call because TCP is a byte stream with no message boundaries.
  • C50 bytes — UDP delivers the most recently sent message first
    Incorrect.UDP doesn't reorder messages (unless they arrive out of order at the network level, which is rare on local networks). Messages arrive in send order for simple local communication.
  • DIt depends on network conditions — UDP may split or merge datagrams
    Incorrect.UDP doesn't merge datagrams at any level. IP fragmentation can split large datagrams at the IP layer, but the receiving IP stack reassembles them before delivering to UDP. The application always gets one complete datagram per recvfrom().

Hint:UDP is message-oriented, not stream-oriented. How does that affect receive behavior?