Episode 1 — Fundamentals / 1.3 — Internet Protocols
1.3.b — How Connection is Established Using TCP (Three-Way Handshake)
In one sentence: Before a single byte of your webpage can flow, the client and server must synchronize by exchanging three special messages — SYN, SYN-ACK, ACK — a ritual called the three-way handshake that opens a reliable, two-way communication channel.
Navigation: ← 1.3.a — What is TCP · 1.3.c — What is UDP →
Table of Contents
- 1. Why a Handshake?
- 2. The Three Steps — Explained
- 3. Sequence Numbers — What Gets Synchronized
- 4. Real-World Analogy — The Phone Call
- 5. What Happens at Each Step (Technical Detail)
- 6. TCP Flags Used in the Handshake
- 7. Timing and Performance
- 8. What Can Go Wrong
- 9. SYN Flood Attack
- 10. Connection Termination — The Four-Way Close
- 11. Key Takeaways
- 12. Explain-It Challenge
1. Why a Handshake?
TCP is connection-oriented — both sides must agree they are ready before data flows. The handshake accomplishes three things:
| Purpose | What it ensures |
|---|---|
| Reachability | Both sides confirm the other is alive and listening |
| Synchronization | Both sides exchange initial sequence numbers (ISNs) so they can track every byte |
| Parameter agreement | Both sides negotiate options: Maximum Segment Size (MSS), Window Scale, SACK support, timestamps |
Without a handshake, the sender would blast data into the void with no idea whether the receiver exists, is ready, or speaks the same "version" of TCP.
2. The Three Steps — Explained
CLIENT SERVER
(wants to connect) (listening on a port)
│ │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ STEP 1: SYN │ │
│ │ "Hey, I want to talk. My starting number │ │
│ │ is X. Are you there?" │ │
│ └──────────────────────────────────────────────┘ │
│ ───────────────────────────────────────────────► │
│ │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ STEP 2: SYN-ACK │ │
│ │ "Yes, I'm here! I acknowledge your X. │ │
│ │ My starting number is Y." │ │
│ └──────────────────────────────────────────────┘ │
│ ◄────────────────────────────────────────────── │
│ │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ STEP 3: ACK │ │
│ │ "Got it! I acknowledge your Y. │ │
│ │ Let's go!" │ │
│ └──────────────────────────────────────────────┘ │
│ ───────────────────────────────────────────────► │
│ │
│ ═══════════ CONNECTION ESTABLISHED ════════════ │
│ │
│ Data can now flow in both directions │
| Step | Who sends | Flag(s) set | What it carries |
|---|---|---|---|
| 1. SYN | Client → Server | SYN | Client's Initial Sequence Number (ISN), MSS, window scale, options |
| 2. SYN-ACK | Server → Client | SYN + ACK | Server's ISN, acknowledgment of client's ISN (client ISN + 1), server's MSS/options |
| 3. ACK | Client → Server | ACK | Acknowledgment of server's ISN (server ISN + 1); can include data in some cases |
3. Sequence Numbers — What Gets Synchronized
Every byte in a TCP connection has a sequence number. The handshake establishes where each side's numbering starts.
CLIENT picks ISN = 1000 SERVER picks ISN = 5000
Step 1: SYN
Client → Server
seq = 1000, SYN flag set
"My stream will start at byte 1000"
Step 2: SYN-ACK
Server → Client
seq = 5000, ack = 1001, SYN + ACK flags set
"My stream starts at 5000. I expect your next byte to be 1001"
Step 3: ACK
Client → Server
seq = 1001, ack = 5001, ACK flag set
"I expect your next byte to be 5001. We're synchronized!"
═══════════════════════════════════════════════════════
After handshake:
• Client sends data starting at seq 1001
• Server sends data starting at seq 5001
• Every byte is tracked; nothing is lost
Why random ISNs? If ISNs always started at 0, an attacker could predict sequence numbers and inject fake packets. Random ISNs make TCP sequence prediction attacks much harder.
4. Real-World Analogy — The Phone Call
┌─────────────────────────────────────────────────────────────────┐
│ THE PHONE CALL ANALOGY │
│ │
│ You (Client) Friend (Server) │
│ │
│ Step 1 — RING RING "Hey, can you hear me?" │
│ (SYN) │
│ │
│ Step 2 — "Yes I can hear you! Can YOU hear ME?" │
│ (SYN-ACK) │
│ │
│ Step 3 — "Yes! I hear you too. Let's talk!" │
│ (ACK) │
│ │
│ ═══════ CONVERSATION BEGINS ═══════ │
│ │
│ Both sides CONFIRMED they can hear each other. │
│ A two-step handshake (just SYN + SYN-ACK) wouldn't work: │
│ the server wouldn't know the client received its response. │
└─────────────────────────────────────────────────────────────────┘
Why not two steps? With only SYN and SYN-ACK, the server sends its ISN but never gets confirmation that the client received it. The third step (ACK) closes the loop — both sides know the other received their ISN.
5. What Happens at Each Step (Technical Detail)
Step 1: Client sends SYN
TCP Segment:
Source Port: 52431 (ephemeral)
Destination Port: 443 (HTTPS)
Sequence Number: 1000 (random ISN)
Ack Number: 0 (not set yet)
Flags: SYN = 1
Window Size: 65535
Options: MSS=1460, Window Scale=7, SACK Permitted, Timestamps
- Client transitions from CLOSED to SYN_SENT state
- The SYN flag consumes one sequence number (so the next byte will be 1001)
Step 2: Server sends SYN-ACK
TCP Segment:
Source Port: 443
Destination Port: 52431
Sequence Number: 5000 (server's random ISN)
Ack Number: 1001 (client's ISN + 1)
Flags: SYN = 1, ACK = 1
Window Size: 65535
Options: MSS=1460, Window Scale=7, SACK Permitted, Timestamps
- Server transitions from LISTEN to SYN_RECEIVED state
- The
ack = 1001says: "I received everything up to byte 1000; send me byte 1001 next"
Step 3: Client sends ACK
TCP Segment:
Source Port: 52431
Destination Port: 443
Sequence Number: 1001
Ack Number: 5001 (server's ISN + 1)
Flags: ACK = 1
Window Size: 65535
- Client transitions to ESTABLISHED state
- Upon receiving this, server also transitions to ESTABLISHED
- Data transfer can begin immediately (client can even piggyback data on this ACK)
6. TCP Flags Used in the Handshake
| Flag | Full name | Purpose |
|---|---|---|
| SYN | Synchronize | "I want to start a connection; here's my ISN" |
| ACK | Acknowledge | "I confirm receipt of your data up to this sequence number" |
| FIN | Finish | "I'm done sending data" (used in connection close, not handshake) |
| RST | Reset | "Something is wrong; abort the connection immediately" |
| PSH | Push | "Deliver this data to the application immediately" |
| URG | Urgent | "This segment contains urgent data" (rarely used) |
During the handshake, only SYN and ACK are used. The combination SYN + ACK (both flags set) in step 2 is why we call it "SYN-ACK."
7. Timing and Performance
How long does a handshake take?
The handshake requires one full round trip (1 RTT):
Time ──────────────────────────────────────────────►
Client Server
│ │
│── SYN ────────────────────────────────► │ ½ RTT
│ │
│ ◄──────────────────────────── SYN-ACK ──│ ½ RTT
│ │
│── ACK ────────────────────────────────► │ ½ RTT (+ data can start)
│ │
Total: ~1.5 RTT before data flows
(but only 1 RTT before client can start sending data)
| Server location | Typical RTT | Handshake cost |
|---|---|---|
| Same data center | < 1 ms | Negligible |
| Same country | 10–40 ms | 10–40 ms |
| Cross-continent | 80–150 ms | 80–150 ms |
| Around the world | 200–300 ms | 200–300 ms |
Why this matters for web performance
For an HTTPS page load, you pay:
- DNS lookup (variable)
- TCP handshake (1 RTT)
- TLS handshake (1 additional RTT with TLS 1.3)
- HTTP request + response (1 RTT)
That's 3 RTTs minimum before any data arrives. With a 150 ms RTT, that's 450 ms of just setup. This is why:
- CDNs reduce RTT by placing servers closer
- HTTP/2 reuses one TCP connection for many requests
- HTTP/3 (QUIC) combines transport and TLS handshake to save round trips
8. What Can Go Wrong
| Problem | What happens | Result |
|---|---|---|
| SYN lost | Client sends SYN, never gets SYN-ACK | Client retries after timeout (typically 1s, then 2s, 4s... exponential backoff) |
| SYN-ACK lost | Server responded but client never got it | Client retries SYN; server may retransmit SYN-ACK |
| ACK lost | Server waits in SYN_RECEIVED | Server retransmits SYN-ACK; client resends ACK |
| Server not listening | No application on that port | Server responds with RST — connection refused |
| Firewall blocks | SYN packet dropped by firewall | Client sees timeout — ERR_CONNECTION_TIMED_OUT |
| Port unreachable | Server sends ICMP port unreachable | Client sees connection refused immediately |
9. SYN Flood Attack
A SYN flood is a denial-of-service (DoS) attack that exploits the handshake.
ATTACKER SERVER
│ │
│── SYN (fake source IP) ────────────────►│ Server allocates memory
│── SYN (fake source IP) ────────────────►│ for half-open connection
│── SYN (fake source IP) ────────────────►│
│── SYN (fake source IP) ────────────────►│ Server's connection table
│── SYN (fake source IP) ────────────────►│ fills up...
│── SYN ... thousands more ... ──────────►│
│ │
│ Server waits for ACKs that never come │ SERVER OVERWHELMED
│ Legitimate users can't connect │ (out of memory/slots)
Defenses
| Defense | How it works |
|---|---|
| SYN cookies | Server encodes state in the SYN-ACK's sequence number instead of storing it; no memory allocated until the ACK returns |
| Rate limiting | Limit SYN packets per source IP per second |
| Firewalls / DDoS protection | Cloud services (Cloudflare, AWS Shield) filter malicious SYN floods before they reach the server |
| Shorter timeouts | Reduce the time half-open connections linger |
10. Connection Termination — The Four-Way Close
When the conversation is done, TCP uses a four-way handshake to close gracefully:
CLIENT SERVER
│ │
│ FIN ──────────────────────────────────► │ "I have no more data to send"
│ │
│ ◄────────────────────────────────── ACK │ "Acknowledged"
│ │
│ (server may still send │
│ remaining data) │
│ │
│ ◄────────────────────────────────── FIN │ "I'm done too"
│ │
│ ACK ──────────────────────────────────► │ "Acknowledged. Connection closed."
│ │
│ ══════ CONNECTION FULLY CLOSED ═══════ │
Why four steps instead of three? Because TCP is full-duplex — each direction closes independently. The server might still have data to send after the client says "I'm done." So each side sends its own FIN and receives its own ACK.
TIME_WAIT state
After the final ACK, the client enters TIME_WAIT for 2 × MSL (Maximum Segment Lifetime, typically 60 seconds). This ensures:
- Late-arriving packets from the old connection don't get confused with a new one
- The server's final FIN can be re-acknowledged if the ACK was lost
11. Key Takeaways
- The three-way handshake (SYN → SYN-ACK → ACK) establishes a TCP connection before any data flows.
- Each side shares a random Initial Sequence Number (ISN) so both can track every byte in the stream.
- The handshake costs 1 RTT — a significant performance factor for distant servers.
- SYN floods exploit the handshake by overwhelming the server with half-open connections; SYN cookies are the primary defense.
- Connection termination uses a four-way close (FIN → ACK → FIN → ACK) because each direction closes independently.
- Understanding the handshake explains why CDNs (closer servers = shorter RTT) and HTTP/2 (one connection for many requests) improve performance.
12. Explain-It Challenge
Without looking back, explain in your own words:
- Draw the three-way handshake on paper with arrows and label each step (SYN, SYN-ACK, ACK).
- Why does TCP need three steps instead of two?
- What is an Initial Sequence Number and why is it randomized?
- What is a SYN flood attack and how do SYN cookies defend against it?
- How does the four-way close differ from the three-way handshake, and why?
Navigation: ← 1.3.a — What is TCP · 1.3.c — What is UDP →