SubnetLayer

The Three-Way Handshake

SYN → SYN-ACK → ACK: how every connection begins

Step 1 of 2 — understand the idea. Read this first and the packet trace will confirm what you already expect, instead of teaching you two things at once.

What you'll be able to do

Before this lesson — it builds directly on:
Before sending real data, the two machines have to agree that they're both there, both willing, and both ready. But there's a subtler problem: TCP numbers every byte, and each side picks its own starting number. Neither side can guess the other's — so each must announce its number AND be told that the announcement was heard. That's two announcements and two confirmations. The clever part is that the middle packet does two jobs at once, so three packets are enough instead of four.
Two people agreeing to talk over a bad radio link. One says "Alpha, do you read me?" The other says "I read you, Alpha — this is Bravo, do you read ME?" And the first says "I read you, Bravo." Only now does either of them start saying anything that matters, because until that third message, Bravo does not know that Alpha can hear the replies.
"Alpha, do you read me?"
SYN — the client announces its own starting number
"I read you, Alpha — this is Bravo"
SYN-ACK — one packet doing both jobs
"I read you, Bravo"
ACK — the client confirms the server's number
the name each gives
the Initial Sequence Number each side chooses at random

Where it breaks down: Radio operators can hear whether the channel is noisy; TCP cannot. It has no idea whether the path is good until it starts losing segments. And a radio check confirms the link, whereas a completed handshake says nothing about whether the application behind the socket is healthy — a server can accept the connection and then never read a byte.

✗ Common misunderstanding: A successful three-way handshake means the application is up and ready.

Why that's wrong: The handshake is completed by the operating system's TCP stack. A listening socket can be accepted by the kernel while the application behind it is hung, still starting, or broken.

Correct model: The handshake proves a socket is listening and the path works in both directions — nothing about application health.

The packets prove it: The handshake trace reaches ESTABLISHED with zero application bytes exchanged; the server's process is never consulted.

✗ Common misunderstanding: The SYN packet carries the first application data.

Why that's wrong: In classic TCP the SYN carries options and the ISN, but no payload — data flows only after the handshake completes. (TCP Fast Open is a separate, later extension.)

Correct model: Handshake first, data second. The SYN's job is synchronising sequence numbers and announcing capabilities.

The packets prove it: Select the SYN in any trace: Len=0, and the payload field is absent entirely.

Watch these fields in the lab: tcp.flags.syn · tcp.sequenceNumber

  1. 1The server has already called listen() and sits in the LISTEN state, doing nothing but waiting. No packets are involved yet.
  2. 2The client's OS picks an unused ephemeral port (here 49512) so this connection's 5-tuple will be unique.
  3. 3Each side independently chooses a random Initial Sequence Number — the starting point for numbering its own outgoing bytes.
  4. 4The client sends SYN, announcing its ISN and its capabilities (MSS, window scale, SACK-permitted, timestamps).
  5. 5The server replies SYN-ACK: acknowledging the client's ISN + 1, announcing its own ISN, and stating its own capabilities.
  6. 6The client sends ACK, acknowledging the server's ISN + 1. Both sequence spaces are now confirmed and the connection is ESTABLISHED — with zero application data sent so far.
Two independent byte streamsOne TCP connection carries two separate byte streams: client to server, and server to client. Each direction has its own sequence number space, its own acknowledgements and its own receive window. Data flowing one way is numbered independently of data flowing the other way.💻 Client🖥️ Serverclient → server streamown seq space · own ACKs · server's window limits itserver → client streamown seq space · own ACKs · client's window limits itThe two streams are numbered independently — ISN(client) has nothing to do with ISN(server).
A connection is two one-way streams sharing a pipe. This is why each side has its own ISN, its own window, and can close its own direction independently.

Watch these fields in the lab: tcp.flags.syn · tcp.flags.ack · tcp.sequenceNumber · tcp.ackNumber

✓ Concept check — before you open the packets

These test the idea, not the trace. You should be able to answer them from the explanation above.

Why does the handshake need three packets rather than two?

A client's SYN carries seq = 5000. What acknowledgement number will the server's SYN-ACK carry, and why?

Now that you understand the concept, observe how it appears in the packet exchange.

The lab runs a real simulated capture — pause, step, click any packet, and inspect every byte.