TCP 3-Way Handshake

intermediate tcp handshake syn ack transport

Before TCP can ship any actual data, the client and server shake hands with three messages: SYN, SYN-ACK, ACK. This sets up sequence numbers and confirms both sides are alive.

In simple language: it’s like calling someone — “Hello?” “Hello!” “Great, let’s talk.” Three turns and we’re ready.

The Three Messages

  1. SYN — Client says “I want to connect. My starting sequence number is X.”
  2. SYN-ACK — Server says “Got it. My starting sequence number is Y, and I acknowledge yours (ack = X+1).”
  3. ACK — Client says “Confirmed. ack = Y+1.” Done — connection is ESTABLISHED.

The Handshake Timeline

CLIENT
SERVER
SYN seq=100
────────────▶
(LISTEN → SYN_RCVD)
(SYN_SENT)
◀────────────
SYN-ACK seq=500, ack=101
ACK seq=101, ack=501
────────────▶
(ESTABLISHED)
CONNECTION ESTABLISHED

Why Three Messages, Not Two?

Both sides need to synchronize sequence numbers AND prove they can hear each other.

  • Message 1: client → server. Server learns client is alive + client’s seq#.
  • Message 2: server → client. Client learns server is alive + server’s seq#.
  • Message 3: client → server. Server learns its message reached the client.

Without the third message, the server wouldn’t know if its SYN-ACK got through.

Sequence Numbers — Why Random?

The initial sequence number (ISN) is chosen pseudo-randomly. Why not start at 0?

  • Security — predictable seq numbers let attackers spoof packets in a session.
  • Avoid collisions — old packets from a previous connection on the same 5-tuple shouldn’t get confused with the new one.

RFC 6528 defines how modern OSes pick ISNs.

Connection States

Each side moves through a state machine. The key states for the handshake:

Client:  CLOSED -> SYN_SENT -> ESTABLISHED
Server:  CLOSED -> LISTEN -> SYN_RCVD -> ESTABLISHED

We can see them live with:

ss -tan         # Linux
netstat -an | grep -E 'SYN|ESTAB'   # macOS / cross-platform

Watching It With tcpdump

sudo tcpdump -i any -n 'tcp[tcpflags] & (tcp-syn|tcp-ack) != 0' and host example.com
# 14:00:01 IP 192.168.1.5.51234 > 93.184.216.34.443: Flags [S], seq 100
# 14:00:01 IP 93.184.216.34.443 > 192.168.1.5.51234: Flags [S.], seq 500, ack 101
# 14:00:01 IP 192.168.1.5.51234 > 93.184.216.34.443: Flags [.], ack 501

[S] = SYN, [S.] = SYN+ACK, [.] = ACK.

SYN Flood Attack

Send tons of SYN packets but never reply with the final ACK. The server keeps half-open connections in SYN_RCVD state, exhausting memory. Mitigation: SYN cookies — the server stores no state until the ACK arrives.

Latency Cost

The handshake takes 1 RTT (round-trip time) before any application data flows. To India ↔ US, that’s ~150ms doing nothing useful. This is one reason QUIC and TLS 1.3 0-RTT exist — to fold the handshake into the first useful message.

TCP Fast Open (TFO)

A modern extension: a client can include data in the initial SYN if it has a valid cookie from a previous connection. Saves an RTT on repeat visits.

Common Gotcha

People say “the handshake exchanges data” — it doesn’t. The handshake just sets up the connection. The first byte of HTTP doesn’t go out until after the third ACK.

Interview Tip

If asked to draw the handshake on a whiteboard, draw two vertical lines (client/server) and three diagonal arrows. Label each with the flags (SYN, SYN-ACK, ACK) and a sample seq/ack. Done — most interviewers want to see exactly that sketch.