The Transport Layer
UDP
PORTS so the packet reaches a program
JrCodex·7 min read
Jr Codex Computer Networks Notes
Level: Intermediate Prerequisites: Chapter 1: Ports, Sockets and Multiplexing Time to complete: ~15 minutes
Table of Contents
- The Minimal Transport
- The Header
- What UDP Does Not Do
- When Less Is More
- Writing UDP Code
- Building Reliability on UDP
- Summary & Next Steps
1. The Minimal Transport
What UDP Adds to IP
─────────────────────────────────────────
PORTS so the packet reaches a program
(Chapter 1)
A CHECKSUM optional in IPv4, mandatory in IPv6
A LENGTH field
That is all. Four fields, eight bytes.
UDP is IP with process addressing bolted on. It
inherits every one of IP's non-guarantees.
─────────────────────────────────────────
The Design Philosophy
─────────────────────────────────────────
UDP is not "TCP without the good parts". It is a
deliberate choice to give the application FULL
CONTROL.
TCP's guarantees cost latency and impose
behaviour. For some applications those costs
exceed the benefit, and the application can do
better with its own logic.
UDP exists so that those applications are not
forced to pay.
─────────────────────────────────────────
2. The Header
Eight Bytes
─────────────────────────────────────────
0 16 31
┌─────────────────┬──────────────────┐
│ Source Port │ Destination Port │
├─────────────────┼──────────────────┤
│ Length │ Checksum │
└─────────────────┴──────────────────┘
Compare TCP's 20-byte minimum header, with
sequence numbers, acknowledgement numbers, flags
and a window (Chapter 3).
Every one of those fields exists to support a
guarantee UDP does not make.
─────────────────────────────────────────
The Checksum's Pseudo-Header
─────────────────────────────────────────
UDP's checksum covers the data, the UDP header,
AND a PSEUDO-HEADER containing the source and
destination IP addresses from the IP layer.
WHY: to detect a packet misdelivered to the wrong
host. Without it, a corrupted IP address could
route a packet to the wrong machine, which would
accept it as valid.
It is a deliberate small violation of layering
(Module 1, Chapter 1), for a good reason. TCP
does the same.
─────────────────────────────────────────
3. What UDP Does Not Do
The Missing Guarantees
─────────────────────────────────────────
NO DELIVERY GUARANTEE
A datagram may be lost. Nothing notices, and
nothing retransmits.
NO ORDERING
Datagrams may arrive in any order — a later one
may take a faster route.
NO DUPLICATE DETECTION
A datagram may arrive twice.
NO CONNECTION
No handshake, no state, no teardown.
NO FLOW CONTROL
A fast sender will overwhelm a slow receiver.
NO CONGESTION CONTROL
UDP does not slow down when the network is
congested. If it did, it would not be UDP.
─────────────────────────────────────────
THE CONGESTION WARNING
─────────────────────────────────────────
This last one is a genuine responsibility, not a
footnote.
TCP's congestion control (Chapter 4) is what
prevents the internet collapsing under load. It
works because nearly all traffic participates.
A high-volume UDP application that does not
implement its own rate limiting is a FREE RIDER:
it takes bandwidth from every well-behaved TCP
flow sharing the path, and TCP will back off
while UDP does not.
If you build a UDP protocol that moves real
volume, implementing congestion control is part
of the job.
─────────────────────────────────────────
4. When Less Is More
Real Uses, and the Reason
─────────────────────────────────────────
DNS (Module 5, Chapter 1)
A query and a reply, both small. Setting up a
TCP connection would triple the latency of a
lookup that takes one round trip. Lost query?
Ask again.
VOICE AND VIDEO CALLS
A retransmitted audio packet arrives after its
moment has passed and is USELESS. Better to
conceal the gap and keep playing. Latency
matters; completeness does not.
ONLINE GAMES
Position updates are superseded ten times a
second. An old one is worthless.
DHCP (Module 3, Chapter 5)
The client has no IP address yet, so it cannot
establish a TCP connection.
NTP, SNMP, syslog
Small, frequent, individually unimportant.
QUIC / HTTP/3 (Chapter 5)
Uses UDP to build a BETTER transport in
userspace — the most interesting case.
─────────────────────────────────────────
THE PRINCIPLE
─────────────────────────────────────────
Use UDP when a LATE packet is worth LESS than a
MISSING one.
For a file, every byte matters and time does not.
──► TCP.
For a live voice call, a packet that arrives
200ms late is worse than silence — it cannot be
played, and waiting for it delays everything
behind it.
──► UDP.
That single question answers the choice almost
every time.
─────────────────────────────────────────
5. Writing UDP Code
import socket
def udp_server(host="0.0.0.0", port=9999):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((host, port))
print(f"UDP listening on {host}:{port}")
while True:
data, addr = s.recvfrom(65535) # ONE datagram, WHOLE — boundaries preserved
print(f"{len(data)} bytes from {addr}")
s.sendto(data.upper(), addr) # no connection; every send names a targetdef udp_client(host, port, message: bytes, timeout=2.0):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(timeout) # ESSENTIAL — nothing else detects loss
try:
s.sendto(message, (host, port)) # no handshake; this is the first packet
data, _ = s.recvfrom(65535)
return data
except socket.timeout:
return None # lost request, lost reply — indistinguishable
finally:
s.close()Three Things to Notice
─────────────────────────────────────────
NO accept(), NO connect() REQUIRED
There is no connection to establish. The first
packet is the request.
recvfrom RETURNS ONE WHOLE DATAGRAM
Message boundaries are preserved (Chapter 1),
so no framing protocol is needed.
A TIMEOUT IS MANDATORY
Without it, a lost packet means waiting
forever. UDP will never tell you.
SIZE LIMIT: keep datagrams under ~1472 bytes on
a standard Ethernet path, so IP does not have to
fragment them (Module 1, Chapter 3). A fragmented
datagram is lost entirely if ANY fragment is
lost.
─────────────────────────────────────────
6. Building Reliability on UDP
Why Anyone Would
─────────────────────────────────────────
To choose which guarantees to pay for.
A game might want: retransmit critical events
(a player died), never retransmit position
updates, and never block one on the other.
TCP cannot express that. It reliably delivers
everything, in order, which means one lost packet
stalls everything behind it — HEAD-OF-LINE
BLOCKING (Chapter 5).
─────────────────────────────────────────
import struct, time
class ReliableChannel:
"""Selective reliability over UDP: some messages are retried, others are not."""
def __init__(self, sock, addr, rto=0.2, max_retries=5):
self.sock, self.addr = sock, addr
self.rto, self.max_retries = rto, max_retries
self.seq = 0
self.pending = {} # seq -> (payload, sent_at, tries)
def send(self, payload: bytes, reliable: bool):
self.seq += 1
header = struct.pack("!IB", self.seq, 1 if reliable else 0)
self.sock.sendto(header + payload, self.addr)
if reliable:
self.pending[self.seq] = (header + payload, time.time(), 0) # track for retry
def on_ack(self, seq: int):
self.pending.pop(seq, None) # acknowledged ──► stop retrying
def tick(self):
"""Call periodically. Retransmit anything unacknowledged past its timeout."""
now = time.time()
for seq, (data, sent, tries) in list(self.pending.items()):
if now - sent < self.rto * (2 ** tries): # exponential backoff
continue
if tries >= self.max_retries:
del self.pending[seq] # give up
continue
self.sock.sendto(data, self.addr)
self.pending[seq] = (data, now, tries + 1)The Honest Caution
─────────────────────────────────────────
TCP is the product of forty years of refinement
against real networks. Reimplementing it badly is
easy and common.
Build on UDP when you need something TCP
genuinely cannot express — selective reliability,
no head-of-line blocking, connection migration.
And prefer using QUIC (Chapter 5), which already
did this work carefully, over writing your own.
─────────────────────────────────────────
7. Summary & Next Steps
Key Takeaways
- UDP adds only ports, a length and a checksum to IP; every field TCP has beyond that exists to support a guarantee UDP does not make.
- UDP does not implement congestion control, which makes a high-volume UDP application a free rider on well-behaved TCP flows unless it limits itself.
- Use UDP when a late packet is worth less than a missing one — the question that decides voice, video and games versus file transfer.
- Message boundaries are preserved, no framing is needed, and a receive timeout is mandatory because nothing else will ever report loss.
Concept Check
- Why does UDP's checksum deliberately include IP addresses from the layer below?
- Why is retransmitting a lost audio packet in a live call worse than concealing the gap?
- What responsibility does a high-volume UDP application take on that a TCP application does not?
Next Chapter
→ Chapter 3: TCP Connections and Reliability
Jr Codex — 1-on-1 Personalized Coaching | Back to Module Index | Back to Computer Networks Index