Course outline · 0% complete

0/30 lessons0%

Course overview →

TCP: the handshake, sequence and ack numbers

lesson 7-2 · ~13 min · 20/30

Building reliability out of unreliable parts

TCP (transmission control protocol) offers the application a very different promise from UDP: a byte stream that arrives complete, in order, exactly once, at a pace the receiver and the network can handle. Nothing in IP provides any of that, so TCP builds every guarantee itself with numbering, acknowledgment, and timers.

Its header is 20 bytes minimum, and every field earns its place.

FieldSizePurpose
Source port2 Bthe sender's port
Destination port2 Bthe receiver's port
Sequence number4 Bposition of the first byte of this segment
Acknowledgment number4 Bnext byte the sender of this segment expects
Data offset4 bitsheader length in 4 byte words, so options can vary
Flags9 bitsSYN, ACK, FIN, RST, PSH, URG, and congestion bits
Window2 Bhow many more bytes the receiver can accept right now
Checksum2 Bcovers header, data, and a pseudo header with the IPs
Urgent pointer2 Balmost unused in practice
Options0 to 40 BMSS, window scale, SACK permitted, timestamps

The flags that carry the state machine:

FlagNameMeaning
SYNsynchronizeopen a connection, here is my starting sequence number
ACKacknowledgethe acknowledgment field is meaningful
FINfinishI have no more data to send
RSTresetabort immediately, this connection is invalid
PSHpushdeliver to the application now, do not wait to fill a buffer

The three way handshake

Before any data moves, both sides must agree that they are talking and exchange starting sequence numbers.

1. Client to server, SYN. "I want a connection. My sequence numbering starts at 1000." That starting value is the ISN (initial sequence number). 2. Server to client, SYN and ACK together. "Accepted. My numbering starts at 5000, and I acknowledge 1001, meaning the next byte I expect from you." 3. Client to server, ACK. "I acknowledge 5001." The connection is now established on both sides and data may flow.

Three segments, one and a half round trips of delay before the first byte of application data. On a 60 ms path that is 90 ms of pure setup, which is the whole motivation for connection reuse in HTTP and for QUIC's faster handshake.

Two details that matter more than they look:

- The ISN is random, not zero. If it were predictable, an attacker who could guess it could inject data into somebody else's connection without seeing any of it. Randomizing it also prevents a delayed segment from an old connection on the same port pair being accepted into a new one. - Every ack is "the next byte I expect", not "the last byte I got". So acknowledging a SYN, which consumes one sequence number even though it carries no data, means acking 1001 after a SYN of 1000. Keeping that definition straight makes the next section simple arithmetic instead of guesswork.

If nothing is listening on the port, the server answers the SYN with RST instead, and the client's connect call returns "connection refused" immediately. If a firewall drops the SYN, nothing comes back and the client retries with doubling waits until it times out. Same broken outcome, completely different diagnosis, which is why the distinction from Lesson 7-1 is so useful.

clientserverSYN seq=1000SYN ACK seq=5000 ack=1001ACK seq=1001 ack=5001data seq=1001 len=100ACK ack=1101, plus data seq=5001 len=500the handshake costs one and a half round trips before any data
The three way handshake, then one segment of data in each direction. Every acknowledgment names the next byte expected.

Sequence and ack arithmetic, worked

Continue the connection above. The client's numbering starts at 1000 and the server's at 5000. Follow the two counters.

StepSegmentseqlenackWhy
1client SYN10000—SYN consumes one number
2server SYN ACK5000010011000 plus 1 for the SYN
3client ACK100105001same rule, other direction
4client data10011005001bytes 1001 through 1100
5server ACK5001011011001 plus 100, next expected
6server data50015001101bytes 5001 through 5500
7client ACK1101055015001 plus 500

Two rules generate every row:

next seq = this seq + bytes of data in this segment
      ack = highest contiguous byte received + 1

The word contiguous is the important one, because TCP acknowledgments are cumulative. Ack 1101 means "I have everything up to 1100", nothing more and nothing less. Now suppose four segments of 100 bytes are sent and the second is lost.

received: 1001-1100, [lost 1101-1200], 1201-1300, 1301-1400
ack sent: 1101, then 1101, then 1101

The receiver keeps repeating ack 1101, because that is the highest contiguous point, even though it is holding 1201 to 1400 in a buffer. Those repeats are duplicate acks, and Lesson 7-3 shows how the sender uses them to detect the loss quickly.

Repeating an ack wastes the information about what did arrive, so an option fixes it. SACK (selective acknowledgment) lets the receiver add "and I also have 1201 to 1400", so the sender retransmits only the missing 100 bytes instead of everything from 1101 onward. It is negotiated in the handshake and is on by default nearly everywhere.

Reading a handshake in a capture

sudo tcpdump -n -i eth0 'tcp port 443 and tcp[tcpflags] & tcp-syn != 0'
11:04:22.118 IP 192.168.1.42.51514 > 93.184.216.34.443:
  Flags [S], seq 2847193021, win 64240,
  options [mss 1460,sackOK,TS val 88213 ecr 0,nop,wscale 7]
11:04:22.176 IP 93.184.216.34.443 > 192.168.1.42.51514:
  Flags [S.], seq 1082441120, ack 2847193022, win 65535,
  options [mss 1400,sackOK,TS val 41022 ecr 88213,nop,wscale 9]
11:04:22.176 IP 192.168.1.42.51514 > 93.184.216.34.443:
  Flags [.], ack 1, win 502, length 0

Everything in this lesson is visible in those three lines.

- [S] is SYN, [S.] is SYN with ACK, and [.] is a bare ACK. - The real ISNs are large random numbers, as promised. After the handshake tcpdump switches to relative numbering, which is why the third line says ack 1. - The gap between the first and second line, 58 ms, is one round trip time measured for free. - MSS (maximum segment size) is advertised by each side: 1460 from the client is 1500 MTU minus 20 IP minus 20 TCP, and the server's 1400 reveals a smaller MTU somewhere on its side, which connects straight back to Lesson 3-3. - wscale 7 is the window scale option, which multiplies the 16 bit window field by 2⁷ = 128 so the window can exceed 65,535 bytes. Without it the bandwidth delay product from Lesson 1-2 would cap throughput on any long path.