← Module 04 · Layer 4: Transport

TCP 3-Way Handshake & Termination

How two hosts agree to start a reliable conversation, built entirely out of the SYN, ACK, and FIN flags from the last topic, and the more careful dance required to end one cleanly.

Opening a connection: The three-way handshake

It's exactly like the ritual that opens a phone call. "Hello, can you hear me?" "Yes, and can you hear me?" "Yes." Three exchanges, not two, because the call needs to be confirmed working in both directions before either side starts talking business. TCP needs the same thing: it's full-duplex, so each side has to pick its own starting sequence number and have the other side confirm it received that number.

THE THREE-WAY HANDSHAKE CLIENT SERVER SYN: seq=100 client proposes a starting sequence number SYN, ACK: seq=300, ack=101 server proposes its own number, and confirms the client's ACK: seq=101, ack=301 client confirms the server's number too, connection is open
Each side's ack number is the other side's sequence number plus one. By the third segment, both sides have proposed a starting number and had it confirmed.
StepDirectionFlagsEstablishes
1Client → ServerSYNThe client's initial sequence number (ISN)
2Server → ClientSYN, ACKThe server's own ISN, and confirmation of the client's
3Client → ServerACKConfirmation of the server's ISN; data can now flow either way
WHY THIS SPECIFIC NUMBER, THREE

Two segments aren't enough: if the client only sent SYN and the server replied SYN ACK, the client would know the server's number, but the server would have no confirmation the client actually received it. A fourth segment isn't needed either, since the third segment's ACK can piggyback directly on top of it without adding a separate step. Three is the minimum that confirms both directions.

Closing a connection: Four-way termination

Because TCP is full-duplex, either side can still have data left to send even after the other side is done. Closing a connection means each direction has to be shut down on its own, which is normally four segments instead of two. The side that closes first sends FIN and enters FIN_WAIT; the other side, now in CLOSE_WAIT, can keep sending data on its still-open half of the connection until it's ready to send its own FIN.

FOUR-WAY TERMINATION CLIENT SERVER FIN client has no more data to send ACK server acknowledges, connection is now half-closed FIN server is done sending too, now it also closes ACK client acknowledges, and enters TIME_WAIT
The gap between step 2 and step 3 can be anywhere from instant to a while: the server keeps its half of the connection open for as long as it still has data to send.
StepDirectionFlagsWhat happens
1Initiator → PeerFINInitiator has no more data to send, enters FIN_WAIT
2Peer → InitiatorACKPeer acknowledges; connection is half-closed, peer enters CLOSE_WAIT
3Peer → InitiatorFINPeer is also done sending, once it's ready
4Initiator → PeerACKInitiator acknowledges, enters TIME_WAIT before fully closing
WHY TIME_WAIT EXISTS

After sending the final ACK, the initiator doesn't close immediately. It waits in TIME_WAIT for a period (typically twice the maximum segment lifetime) in case that final ACK got lost and the peer retransmits its FIN. Without this wait, a lost ACK could leave the peer stuck resending a FIN that never gets acknowledged. It's also why a server restarted quickly can sometimes fail to rebind a port that's still finishing TIME_WAIT from a previous connection.

WHEN RST REPLACES A CLEAN CLOSE

Not every connection ends this gracefully. A RST (reset) tears a connection down immediately, with no half-closed state and no TIME_WAIT: it's what happens when a segment arrives for a port nothing is listening on, or when an application aborts a connection after an error instead of finishing its data cleanly.