Day 16: TCP in depth: handshake, slow start, congestion control
TCP: reliable delivery over an unreliable network
TCP guarantees ordered, reliable, byte-stream delivery between two endpoints — even though the underlying network (IP) makes no such promise and can drop, duplicate, or reorder packets. It does this with sequence numbers, acknowledgments, and retransmission.
The three-way handshake
Before any data flows, client and server establish a connection: SYN (client: "I want to connect, my starting sequence number is X") → SYN-ACK (server: "acknowledged, here's my starting sequence number Y") → ACK (client: "acknowledged"). Only after this handshake can application data be sent.
Client Server
|------ SYN (seq=X) --------->|
|<--- SYN-ACK (seq=Y,ack=X+1)--|
|------ ACK (ack=Y+1) -------->|
| connection established |Slow start & congestion control
TCP doesn't blast at full speed immediately — slow start begins with a small congestion window and doubles it each round trip until it detects packet loss (a signal of congestion), then backs off. This is TCP self-regulating to avoid overwhelming the network — the same reason a new connection to a far-away server often feels slower for the first few round trips than a long-lived one.
Why this matters for real performance work
This is exactly why HTTP keep-alive (reusing one TCP connection for many requests, Day 20) is a meaningful performance win — every new TCP connection restarts slow start from scratch.
Ephemeral ports
A server listens on a well-known port (443 for HTTPS). The client picks a temporary, high-numbered ephemeral port (typically 32768–60999) for its side of the connection — this is what lets one client machine have thousands of simultaneous connections to the same server port.
Key terms
- Three-way handshake
- SYN → SYN-ACK → ACK — how TCP establishes a connection before any data flows.
- Slow start
- TCP starting with a small congestion window and growing it until packet loss signals congestion.
- Ephemeral port
- A temporary, client-side port number used for one connection's lifetime.
Why does keeping a TCP connection alive (HTTP keep-alive) improve performance beyond just saving handshake time?