The TCP Three-Way Handshake, Captured
A real TCP connection captured on loopback with a raw socket: SYN, SYN-ACK, ACK, data and teardown with sequence numbers explained, plus the RST from a closed port and how SYN floods work.
The TCP three-way handshake sets up a connection with three packets: the client sends SYN with its initial sequence number x, the server replies SYN-ACK with its own number y and ack x + 1, and the client sends ACK with y + 1. Interviewers expect why three: each side must confirm the other received its sequence number.
Before sending data, TCP agrees on starting sequence numbers with three packets: SYN, SYN-ACK, ACK. Closing takes FIN and ACK in each direction. A raw-socket capture of a real local connection shows each packet with its flags and numbers, and a closed port answers the first SYN with RST.
- In the TCP handshake the client sends SYN with sequence number x, the server replies SYN-ACK with its own number y and ack = x + 1, and the client sends ACK with ack = y + 1.
- The TCP SYN and FIN flags each consume one sequence number even though they carry no data, which is why the handshake acknowledges x + 1 and y + 1.
- Opening a TCP connection costs one round trip before the client can send data, and TLS adds more round trips on top of that.
- Closing a TCP connection takes FIN and ACK in each direction, and the side that closes first enters TIME_WAIT, which lasts 60 seconds on Linux.
- A SYN to a port with no listener is answered with RST and connect fails immediately with ConnectionRefusedError, while a timeout suggests a firewall or unreachable host.
- SYN cookies defend against SYN floods by encoding connection details into the server's initial sequence number, so the server keeps no state for half-open connections.
01What TCP has to agree on
TCP gives applications a reliable, ordered byte stream on top of an unreliable network. To do that, each side numbers the bytes it sends (sequence numbers) and acknowledges what it receives. Before data moves, the two ends must tell each other where their numbering starts, and confirm that the other side is actually there and reachable in both directions. That exchange is the handshake.
Each side picks an initial sequence number (ISN). It is random rather than zero, so that stray packets from an old connection between the same addresses are unlikely to be mistaken for part of a new one, and so that attackers cannot guess it easily.
02The three packets
- The client sends SYN (synchronise) carrying its ISN, say x.
- The server replies SYN-ACK: it sets its own SYN with its ISN y, and acknowledges the client with ack = x + 1, meaning "I expect byte x + 1 next".
- The client sends ACK with ack = y + 1.
Now both sides know each other's starting numbers, and each has proved it can both send and receive, so the connection is established. The SYN flag occupies one sequence number even though it carries no data, which is why the acknowledgements are x + 1 and y + 1. Opening a connection costs one round trip before the client can send data. TLS adds more round trips on top of that.
03A real capture
I opened a raw packet socket on the loopback interface, then had a client connect to a local server, send 5 bytes (hello), receive 6 bytes (pong!!) and close. Numbers below are shown relative to each side's ISN, so 1 means ISN + 1. The loopback interface shows each packet twice in a raw capture, and the list below has the duplicates removed.
C->S SYN
S->C SYN+ACK ack 1
C->S ACK seq 1 ack 1
C->S ACK+PSH seq 1 ack 1 5 bytes of data
S->C ACK ack 6
S->C ACK+PSH seq 1 ack 6 6 bytes of data
C->S ACK ack 7The first three lines are the handshake. The client's 5 bytes advanced its sequence number from 1 to 6, so the server acknowledged ack 6. The server's 6 bytes took its number from 1 to 7, acknowledged as ack 7. The PSH flag asks the receiver to hand data to the application promptly. Real networks add other things this loopback trace hides, such as options (window scaling, selective acknowledgements) negotiated in the SYN packets.
04Closing the connection
Closing is a four-step exchange because each direction of the stream is closed independently. In the capture the server closed first:
S->C ACK+FIN seq 7 ack 6
C->S ACK ack 8
C->S ACK+FIN seq 6 ack 8
S->C ACK ack 7The server sent FIN (its sequence number 7, consuming one number, so the client acknowledged 8). The client acknowledged, then sent its own FIN, and the server acknowledged that. The side that closes first enters TIME_WAIT afterwards and keeps the connection state for a minute or more (60 seconds on Linux, up to 2 x MSL in the RFC), in case its last ACK was lost and the other side resends its FIN. This is why a busy server can show thousands of sockets in TIME_WAIT.
05When nobody is listening
I also connected to a port with no server. The capture showed just two packets:
C->S SYN
S->C ACK+RST ack 1The operating system replied with a reset, and the client's connect raised ConnectionRefusedError immediately. This is the difference between "refused" and "timed out". A refusal means the host is up and nothing listens on that port. A timeout means the SYN got no answer at all, which suggests a firewall silently dropping packets or an unreachable host.
06SYN floods and SYN cookies
When a server gets a SYN, it normally reserves memory for the half-open connection and waits for the final ACK. An attacker can send huge numbers of SYNs from fake addresses and never complete them, filling the table (a SYN flood), so real clients are refused.
SYN cookies are the standard defence. Under load, the server encodes the connection details into the ISN it sends back, a keyed hash of the addresses, ports and a time value, and keeps no state. If a legitimate client returns the ACK, the server recomputes the cookie, checks it, and rebuilds the connection. Attackers who never reply cost the server almost nothing. The trade-off is that some TCP options cannot be stored in the cookie, so they may be dropped in this mode. Other measures include rate limiting and larger backlog queues.
07Common interview questions
Q: Why three steps and not two?
A: Each side must confirm the other received its sequence number. Two packets would leave the server unsure the client got its SYN-ACK.
Q: Why is the ISN random?
A: To avoid confusion with old packets from earlier connections and to make blind spoofing hard.
Q: What does ack = x + 1 mean?
A: The next byte the receiver expects. SYN and FIN each use up one sequence number.
Q: Why does closing need four packets?
A: Each direction closes independently, so each side sends its own FIN and gets its own ACK.
Q: What is TIME_WAIT?
A: A state kept by the side that closes first, to handle a lost final ACK and to let old packets expire.
Q: What does RST in reply to a SYN mean?
A: Nothing is listening on that port.