TCP and UDP are the two main transport-layer protocols. They both deliver data between processes, but with different trade-offs.
In simple language: TCP is a reliable phone call — connection, ordering, retries. UDP is a postcard — fire it and hope it arrives.
The Core Difference
- TCP (Transmission Control Protocol) — connection-oriented, reliable, ordered, slower.
- UDP (User Datagram Protocol) — connectionless, unreliable, unordered, fast and simple.
Neither is “better” — they’re tools for different jobs.
Side-by-Side Comparison
Header Sizes
TCP header (20 bytes minimum, more with options):
| Src Port | Dst Port | Seq # | Ack # | Flags | Window | Checksum | Urgent |
UDP header (just 8 bytes):
| Src Port | Dst Port | Length | Checksum |
That tiny UDP header is part of why it’s fast — less overhead per packet.
When TCP Wins
We need the data to arrive completely and in order:
- HTTP / HTTPS — every byte of an HTML page must be correct.
- SSH — command-line characters can’t get scrambled.
- Email (SMTP, IMAP, POP3) — losing parts of an email is unacceptable.
- File transfer (FTP, SFTP) — corrupted files are useless.
- Database connections — every query and result must land intact.
When UDP Wins
We care about speed more than perfection, or we’re handling our own reliability:
- DNS — single small query/response. Retry by sending again. (DNS over TCP exists for big responses but UDP is the default.)
- Video calls / VoIP — a missed millisecond of audio is fine. Waiting for retries would freeze the call.
- Online gaming — same idea. Stale state is worse than lost state.
- Video streaming (some) — many streamers use UDP-based protocols (QUIC, RTP).
- NTP — time sync wants minimal latency.
- DHCP — basic broadcast bootstrapping.
QUIC — UDP With Reliability On Top
QUIC (the protocol behind HTTP/3) runs over UDP but rebuilds reliability, ordering, and congestion control in user space. Why? Because TCP is implemented in the kernel and slow to evolve. UDP gives QUIC a clean slate.
So yes — modern HTTPS often runs on UDP. The world is weirder than the textbooks suggest.
A Simple UDP Example
# Server
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
s.bind(('0.0.0.0', 9999))
data, addr = s.recvfrom(1024)
print(f'got {data!r} from {addr}')
s.sendto(b'pong', addr)
# Client
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(b'ping', ('127.0.0.1', 9999))
print(s.recvfrom(1024))
No connection, no handshake. Just send.
Common Gotcha
UDP doesn’t guarantee delivery — but on a healthy LAN, packet loss is near zero. Devs sometimes ship UDP apps that “work in dev” and fall apart on a real network. If we use UDP, we either don’t care about loss or we build our own retry logic.
Interview Tip
When asked “TCP or UDP for X?” — pick based on the question’s hint. “Real-time” or “low latency” or “it’s okay to lose some” → UDP. “File”, “reliable”, “in order” → TCP. Bonus points for mentioning QUIC.