Skip to content

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

3-Way Handshake

Before any data flows, TCP establishes a connection with three segments:1

  1. SYN — the client sends a segment with SYN set and its own initial sequence number (ISN)
  2. SYN-ACK — the server responds with both SYN and ACK set: its own ISN, plus an acknowledgment of the client's ISN + 1
  3. ACK — the client acknowledges the server's ISN + 1, and the connection moves to ESTABLISHED

Connection Termination

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

  1. Side A sends FIN (no more data from A)
  2. Side B sends ACK
  3. Side B sends its own FIN when it's also done sending
  4. 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

TCP State Diagram

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 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

Flow Control: 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


  1. Wikipedia contributors. (2026, August 28). Transmission Control Protocol. Wikipedia, The Free Encyclopedia. https://en.wikipedia.org/wiki/Transmission_Control_Protocol ↩↩↩↩↩↩

  2. 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 ↩

  3. Allman, M., Paxson, V., & Blanton, E. (2009). TCP congestion control (RFC 5681). IETF. https://www.rfc-editor.org/rfc/rfc5681 ↩