TCP
A reliable byte stream built from numbered segments and acknowledgements.
The header of a SYN
The first segment of every TCP connection, field by field. Watch the flag byte: eight switches, one of which is on.
Whole frame
C8 22 00 50 00 00 03 E8 00 00 00 00 60 02 FA F0 D2 EB 00 00 02 04 05 B4: a request to open a connection from port 51234 to port 80, starting at sequence 1000, willing to receive 1460-byte segments.
| Field | Offset | Example value | Meaning |
|---|---|---|---|
| Source port | Byte 0–1 | 0xC822 = 51234 | The client's ephemeral port. Together with both IP addresses and the destination port it identifies this connection: the 4-tuple. |
| Destination port | Byte 2–3 | 0x0050 = 80 (HTTP) | The service being contacted. 80 is HTTP (443 would be HTTPS, 22 SSH, 25 SMTP). |
| Sequence number | Byte 4–7 | 1000 (ISN) | Every byte sent gets a number. In a SYN this field carries the Initial Sequence Number (ISN) the sender will count from. The SYN itself consumes one number, so the first data byte will be ISN + 1. Real stacks pick a random ISN; 1000 is used here for readability. |
| Acknowledgment number | Byte 8–11 | 0 (unused, ACK flag off) | 'I have received everything up to here; send me this byte next.' Meaningless in a first SYN, so it is 0 and the ACK flag stays off. |
| Data offset | Byte 12, bits 7–4 | 6 words = 24 bytes | Header length in 32-bit words, so the receiver knows where the data starts. 6 × 4 = 24 bytes: the 20-byte base header plus 4 bytes of options. |
| Reserved | Byte 12, bits 3–0 | 0 | Reserved for future use, sent as 0. |
| Flags | Byte 13 | 0x02 = SYN | Eight one-bit switches that say what kind of segment this is. A SYN has only SYN set. |
| Window size | Byte 14–15 | 0xFAF0 = 64240 | Flow control: how many more bytes I can buffer. The sender must not have more than this many unacknowledged bytes in flight. |
| Checksum | Byte 16–17 | 0xD2EB (✓) | Covers a pseudo-header (source and destination IP, protocol 6, TCP length), the header and the data. Computed for real here: 0xD2EB. Mandatory, unlike UDP in IPv4. |
| Urgent pointer | Byte 18–19 | 0 | Only meaningful when URG is set. Practically unused. |
| Option kind | Byte 20 | 2 = MSS | Options come as kind, length, value. Kind 2 = Maximum Segment Size. |
| Option length | Byte 21 | 4 | The whole option is 4 bytes (kind, length, 2 value bytes). |
| MSS value | Byte 22–23 | 0x05B4 = 1460 | 'The largest TCP payload I can take in one segment': 1460 = 1500-byte Ethernet MTU minus 20 (IP) minus 20 (TCP). |
Overview
IP may drop, duplicate and reorder packets. TCP hides that: it numbers every byte, makes the receiver acknowledge what arrived, retransmits what did not, and reassembles the stream in order. The application just sees a pipe that delivers bytes reliably.
A connection starts with a three-way handshake and ends with FINs. In between, the window size (flow control) and the congestion window (congestion control) decide how fast the sender may go.
Key facts
- Header
- 20 bytes (up to 60)
- IP protocol number
- 6
- Delivery
- Reliable, ordered
- Connection
- 3-way handshake, 4-way close
- Identified by
- (src IP, src port, dst IP, dst port)
- Standard
- RFC 9293
Opening a connection
Three segments set up the connection, then data and its acknowledgement. Follow the sequence numbers.
Whole exchange
Three segments to open, then every byte is numbered and every segment is acknowledged. That bookkeeping is what turns an unreliable packet network into a reliable byte stream.
11. SYN: shall we talk?
The client picks an initial sequence number (1000) and asks to open a connection. The server is already listening on port 80.
22. SYN-ACK: yes, and here is mine
The server acknowledges 1001 (the SYN used up number 1000, so it expects 1001 next) and announces its own initial sequence number, 5000. One segment does both jobs.
33. ACK: connection open
The client acknowledges 5001. Both sides now know the other's starting number and that the other can hear them. The connection is established; data may flow in both directions.
4First data: an HTTP request
The client sends 100 bytes (say an HTTP GET). They occupy sequence numbers 1001 to 1100. PSH asks the server to hand them to the application immediately.
5ACK: got all 100 bytes
ack=1101 means 'everything up to 1100 has arrived, send 1101 next'. If this ACK never came, the client would retransmit the data after a timeout.
Closing a connection
Four segments, because each direction closes on its own.
Whole exchange
FIN, ACK, FIN, ACK: each direction is closed on its own. TIME_WAIT keeps the client's port reserved a little longer so stray late packets from this connection cannot confuse the next one.
11. FIN: I am done sending
The client has no more data and says so. FIN uses up one sequence number. The client may still receive.
22. ACK: understood
The server acknowledges the FIN. The client's half of the connection is closed; the server's half is still open and may keep sending.
33. FIN: now I am done too
When the server's application has closed its socket, the server sends its own FIN. Closing is two independent one-way shutdowns, which is why it takes four segments.
44. ACK: goodbye
The client acknowledges the server's FIN. The server closes immediately; the client waits in TIME_WAIT (about 60 s, twice the maximum segment lifetime) in case this ACK is lost and the server resends its FIN.
Where you meet it
- HTTP/1.1 and HTTP/2, HTTPS (with TLS), SSH, SMTP, databases
- Anything where losing or reordering bytes is unacceptable
- Not for real-time media: a lost segment stalls everything behind it (head-of-line blocking)
Watch out for
- Sequence numbers count bytes, not segments, and SYN and FIN each consume one number even though they carry no data.
- Wireshark shows relative sequence numbers by default; the real ISN is a random 32-bit value.
- A SYN with no SYN-ACK is the signature of a firewall drop or a dead host. A RST in reply means the port is closed.
- Many 'slow' connections are really lost segments waiting for a retransmission timeout.
Standards
- RFC 9293: Transmission Control Protocol
- RFC 1071: Internet Checksum