TCP¶
Summary
- TCP (Transmission Control Protocol) is a connection-oriented, transport-layer protocol that turns IP's unreliable, best-effort packet delivery into a reliable, ordered byte stream — every byte sent arrives, in order, exactly once, or the connection reports an error.
- It does this through four core mechanisms, each covered in its own section below: a formal connection setup/teardown, sequence numbers and acknowledgments for reliability, a sliding window for flow control, and congestion control to avoid overwhelming the network itself.
- Currently specified by RFC 9293 (2022), which consolidates the original 1981 RFC 793 plus decades of accumulated updates into a single current document.1
3-Way Handshake¶
3-Way Handshake
Before any data flows, TCP establishes a connection with three segments:1
- SYN — the client sends a segment with
SYNset and its own initial sequence number (ISN) - SYN-ACK — the server responds with both
SYNandACKset: its own ISN, plus an acknowledgment of the client's ISN + 1 - ACK — the client acknowledges the server's ISN + 1, and the connection moves to
ESTABLISHED
Connection Termination¶
Connection Termination
Closing a TCP connection is a four-step exchange, because TCP allows a half-close — one side can stop sending while still receiving:1
- Side A sends
FIN(no more data from A) - Side B sends
ACK - Side B sends its own
FINwhen it's also done sending - Side A sends the final
ACK
An abrupt close instead uses RST — no negotiation, no acknowledgment expected, the connection is simply torn down immediately, typically in response to an unrecoverable error.
TCP State¶
A simplified TCP state diagram1
Every TCP connection is, at any given moment, in exactly one of 11 defined states:
| State | Applies To | Description |
|---|---|---|
LISTEN |
Server | Waiting for a connection request from any remote TCP endpoint |
SYN-SENT |
Client | Waiting for a matching connection request after having sent a connection request |
SYN-RECEIVED |
Server | Waiting for a confirming connection request acknowledgment after having both received and sent a connection request |
ESTABLISHED |
Server and client | An open connection; data received can be delivered to the user — the normal state for the data transfer phase of the connection |
FIN-WAIT-1 |
Server and client | Waiting for a connection termination request from the remote TCP, or an acknowledgment of the connection termination request previously sent |
FIN-WAIT-2 |
Server and client | Waiting for a connection termination request from the remote TCP |
CLOSE-WAIT |
Server and client | Waiting for a connection termination request from the local user |
CLOSING |
Server and client | Waiting for a connection termination request acknowledgment from the remote TCP |
LAST-ACK |
Server and client | Waiting for an acknowledgment of the connection termination request previously sent to the remote TCP (which includes an acknowledgment of its connection termination request) |
TIME-WAIT |
Server or client | Waiting for enough time to pass to be sure that all remaining packets on the connection have expired |
CLOSED |
Server and client | No connection state at all |
The 11 TCP States
Why TIME-WAIT lingers
TIME-WAIT specifically waits for 2×MSL (Maximum Segment Lifetime) — insurance against a delayed final ACK or FIN arriving after the connection thinks it's done, and against a new connection reusing the same port/address pair while old segments from the previous connection might still be in flight. This is why a server closing and reopening many short-lived connections in quick succession can accumulate a large number of visible TIME-WAIT sockets.
TCP Header Format¶
TCP Header Format1
Every TCP segment starts with a header of at least 20 bytes (up to 60 bytes with options):
| Field | Size | Purpose |
|---|---|---|
| Source Port | 16 bits | The sending application's port |
| Destination Port | 16 bits | The receiving application's port |
| Sequence Number | 32 bits | The position of this segment's first byte in the overall stream |
| Acknowledgment Number | 32 bits | The next byte the sender of this segment expects to receive (valid when ACK is set) |
| Data Offset | 4 bits | The header length, in 32-bit words — where the actual data begins |
| Reserved | 4 bits | Reserved, must be zero |
| Flags (Control Bits) | 8 bits | CWR, ECE, URG, ACK, PSH, RST, SYN, FIN — see below |
| Window Size | 16 bits | How many bytes the sender of this segment is currently willing to receive |
| Checksum | 16 bits | Error-detection over the header, data, and a pseudo-header |
| Urgent Pointer | 16 bits | Offset to urgent data, valid only when URG is set |
| Options | Variable (0–40 bytes) | Optional extensions — MSS, window scaling, timestamps, SACK, and others |
TCP Header Fields
TCP Flags¶
Eight single-bit flags control what a segment actually does:
| Flag | Meaning |
|---|---|
SYN |
Synchronize sequence numbers — sent to open a connection |
ACK |
The Acknowledgment Number field is valid — set on every segment except the very first SYN |
FIN |
The sender has no more data to send — begins a graceful close |
RST |
Abruptly reset the connection — used for errors, not a normal close |
PSH |
Push the data to the receiving application immediately, rather than buffering it |
URG |
The Urgent Pointer field is valid — marks priority data (rarely used in modern traffic) |
ECE |
ECN-Echo — signals ECN capability during the handshake, or reports congestion seen in transit |
CWR |
Congestion Window Reduced — the sender confirms it reduced its congestion window in response to ECE2 |
TCP Header Flags
Flow Control: The Sliding Window¶
TCP sequence numbers and receive windows behave very much like a clock. The receive window shifts each time the receiver receives and acknowledges a new segment of data. Once it runs out of sequence numbers, the sequence number loops back to 0.1
The Window Size field lets the receiver tell the sender exactly how much unacknowledged data it's currently willing to buffer — preventing a fast sender from overwhelming a slow receiver. As the receiver's application consumes buffered data, the window "slides" forward, opening up room for more.
A window of zero stalls the sender
If a receiver's buffer fills completely, it advertises a window size of 0, telling the sender to stop entirely until the receiver sends a follow-up segment announcing more room.
The raw 16-bit Window Size field alone caps out at 65,535 bytes — far too small for modern high-bandwidth links — so the Window Scale option, negotiated during the handshake, multiplies the advertised window by a much larger factor.
Congestion Control¶
Flow control protects the receiver; congestion control protects the network — a well-behaved TCP sender deliberately limits how much unacknowledged data it has in flight to avoid overwhelming routers and links along the path, entirely independent of what the receiver's window allows.3
- Slow start — a new connection begins conservatively, then rapidly increases its sending rate as ACKs confirm the network can handle it
- Congestion avoidance — once a threshold is reached, growth slows to a more cautious, incremental rate
- Fast retransmit / fast recovery — repeated duplicate ACKs (a sign of a single lost segment, not full congestion) trigger an immediate retransmission, without waiting for a full RTO timeout
Several different congestion control algorithms implement this same general strategy differently — Reno (the classic baseline), CUBIC (Linux's long-standing default), and BBR (Google's newer, model-based approach that estimates actual available bandwidth rather than reacting purely to loss).
Useful Resources¶
- IETF — RFC 9293: Transmission Control Protocol (TCP) — the current, consolidated TCP specification
- IETF — RFC 793: Transmission Control Protocol — the original 1981 specification
- IETF — RFC 5681: TCP Congestion Control
- IETF — RFC 6298: Computing TCP's Retransmission Timer
- IETF — RFC 3168: The Addition of Explicit Congestion Notification (ECN) to IP
-
Wikipedia contributors. (2026, August 28). Transmission Control Protocol. Wikipedia, The Free Encyclopedia. https://en.wikipedia.org/wiki/Transmission_Control_Protocol ↩↩↩↩↩↩
-
Ramakrishnan, K., Floyd, S., & Black, D. (2001). The addition of Explicit Congestion Notification (ECN) to IP (RFC 3168). IETF. https://www.rfc-editor.org/rfc/rfc3168 ↩
-
Allman, M., Paxson, V., & Blanton, E. (2009). TCP congestion control (RFC 5681). IETF. https://www.rfc-editor.org/rfc/rfc5681 ↩




