Networking · TCP vs UDP

TCP vs UDP

One promises delivery and order. The other promises nothing — and that’s sometimes exactly what you want.

Networking Basics → Interview
01

TCP — the Reliable Stream

TCP turns the internet’s unreliable packets into a reliable, ordered byte stream. It numbers every byte (sequence numbers), the receiver acknowledges what arrived (ACKs), and anything unacknowledged is retransmitted. Out-of-order packets are reordered; duplicates are dropped; a checksum catches corruption.

GuaranteeHow TCP does it
DeliveryACK + retransmission timers
OrderSequence numbers, receiver reorders
IntegrityChecksum per segment
Flow controlReceive window — don’t drown a slow receiver
Congestion controlcwnd — don’t drown the network (slow start, AIMD)
02

The Three-Way Handshake

Before any data, TCP establishes a connection so both sides agree on starting sequence numbers:

Client Server SYN (seq=x) SYN-ACK (seq=y, ack=x+1) ACK (ack=y+1) — connection established, data flows —
Closing takes four steps (FIN → ACK, FIN → ACK) because each direction closes independently. The side that closes first lingers in TIME_WAIT to catch stray packets.
03

UDP — Fire and Forget

UDP adds almost nothing to IP: ports, a length, an optional checksum. No handshake, no ACKs, no ordering, no retransmission. A datagram either arrives whole or not at all. That sounds bad — until latency matters more than completeness.

Choose UDP when
  • Latency beats reliability — voice, video, gaming
  • You do your own reliability (QUIC, game netcode)
  • Tiny request/response — DNS queries
  • Broadcast / multicast needed
Choose TCP when
  • Every byte must arrive — files, APIs, pages
  • Order matters — streams, databases
  • You don’t want to reinvent congestion control
HTTP/3 runs on UDP — via QUIC, which rebuilds reliability, ordering and TLS in userspace. Why? TCP’s head-of-line blocking: one lost segment stalls every stream behind it. QUIC retransmits per-stream instead.
04

Both in 10 Lines of Python

Python — TCP vs UDP client
import socket

# TCP — connect, then stream
t = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
t.connect(("example.com", 80))      # 3-way handshake here
t.sendall(b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")

# UDP — no connection, just send
u = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
u.sendto(b"hello", ("example.com", 9999))  # may vanish; nobody tells you

SOCK_STREAM vs SOCK_DGRAM — the entire choice is one constant. Everything else (handshakes, ACKs, ordering) the kernel does for you, or doesn’t.

05

Interview Questions

Why does TCP need a 3-way handshake, not 2?

Both sides must know the other can send AND receive. Two ways would confirm only one direction’s sequence number; the third message proves the client heard the server’s SYN, protecting against stale duplicates opening ghost connections.

What is head-of-line blocking?

TCP delivers bytes in order, so one lost segment blocks delivery of everything after it — even bytes already received — until retransmission arrives. QUIC/HTTP-3 avoids it with independent streams over UDP.

Flow control vs congestion control?

Flow control protects the receiver (receive window advertised in ACKs). Congestion control protects the network (cwnd grown/shrunk by slow start and AIMD on loss). Effective window = min of both.

Why is DNS on UDP?

A query fits one datagram; a handshake would triple the latency for a single round-trip exchange. On truncation or for zone transfers, DNS falls back to TCP.

Quick Quiz

1. Which is NOT a TCP guarantee?
2. The three-way handshake messages, in order:
3. HTTP/3 runs on top of…
4. Flow control exists to protect…
5. A lost UDP datagram is…