Networking

TCP — Transmission Control Protocol

A connection-oriented transport built on top of IP that turns IP's best-effort, unordered packet delivery into a reliable, ordered byte stream — at the cost of connection setup, state, and variable latency.

Quick reference
What it is
A connection-oriented transport that turns IP's unreliable packets into a reliable, ordered byte stream.
Mental model
A phone call: you dial first (handshake), talk in order, and both sides know if the line drops.
Key numbers
3-way handshake before any data flows; minimum 20-byte header; retransmission on unacknowledged segments.
Reach for it when
You need guaranteed, in-order delivery and can accept connection setup cost and variable latency.

Three-way handshake

Before any data flows, both sides synchronize initial sequence numbers:

  1. SYN — client picks an initial sequence number and sends it.
  2. SYN-ACK — server acknowledges the client's SYN and sends its own.
  3. ACK — client acknowledges the server's SYN. Connection is now established.

This is why TCP has connection setup latency that UDP doesn't — at least one full round-trip before the first byte of application data can even be sent.

TCP three-way handshake: SYN from the client, SYN-ACK from the server, ACK from the client, after which the connection is established and data can flow Client Server SYN, seq=x SYN-ACK, seq=y, ack=x+1 ACK, ack=y+1 Connection established — application data flows next
One full round trip (SYN, then SYN-ACK) has to complete before the client's ACK — and therefore any application data — can even be sent.

How reliability actually works

Every byte sent has a sequence number. The receiver sends back acknowledgments (ACKs) naming the next byte it expects. If the sender doesn't see an ACK within a computed retransmission timeout, it resends the unacknowledged data — TCP doesn't require IP to retry anything; it achieves reliability entirely by retransmitting from the endpoints.

Because segments carry sequence numbers, the receiver can also reorder packets that arrived out of order (a normal occurrence when IP routes packets independently) before handing bytes to the application in the correct order.

A lost segment triggers no immediate signal; only after the retransmission timeout expires with no ACK does the sender resend it, which the receiver then acknowledges Sender Receiver seq=100 — lost in transit retransmission timeout (RTO) expires — sender has seen no ACK seq=100 (retransmitted) ACK=101
Loss is invisible to TCP until the timeout fires — there's no "packet lost" signal from the network itself, only the absence of an expected ACK.

Flow control and windows

The receiver advertises a window size — how many unacknowledged bytes it's currently willing to buffer — preventing a fast sender from overrunning a slow receiver. Separately, congestion control (e.g. slow start, congestion avoidance) makes the sender ramp up its send rate cautiously and back off sharply on loss, to avoid overwhelming the network path itself rather than just the receiver.

Connection teardown

A graceful close uses a FIN/ACK exchange from each side independently (TCP connections are full-duplex, so each direction closes separately). The side that closes first enters TIME_WAIT for a period to absorb any stray late segments before fully releasing the connection — the reason a server under heavy short-lived-connection churn can accumulate many sockets in that state.

TCP vs. UDP: why and when

Neither is "better" — they're opposite tradeoffs of the same problem, and the right choice depends entirely on what a dropped or out-of-order packet should mean to the application. A common early misconception is that "TCP/IP" and "UDP" are somehow different families — they're not. Both TCP and UDP sit at the exact same layer, built directly on the exact same IP underneath; "TCP/IP" is just the historical name of the whole suite, not a claim that UDP is somehow separate from it. See OSI vs. TCP/IP Model for the full explanation of that naming.

TCPUDP
Connection setup3-way handshake, one RTT before dataNone — first packet is the data
Delivery guaranteeRetransmits until acknowledgedNone — lost is lost
OrderingGuaranteed, reassembled by sequence numberNone — datagrams can arrive in any order
Message boundariesNone — byte streamPreserved — one send is one receive
Header overhead20+ bytes8 bytes
Congestion controlBuilt in — backs off automatically under network loadNone by default — a UDP sender can keep blasting a congested link unless the application adds its own backoff
Choose it whenCorrectness of every byte matters more than latency (file transfer, control commands, FOTA)Low, predictable overhead matters more than guaranteed delivery, or you'll build your own reliability (real-time media, telemetry, discovery)
How to actually think about the tradeoff

Ask one question: is a late retransmission worse than the original loss?

Everything in the table above falls out of that one distinction. It's also why a newer transport, QUIC, exists at all: it builds TCP-like reliability on top of UDP instead of using TCP directly, to get reliability without inheriting some of TCP's specific costs — see that page for why that's not a contradiction.

Real-world applications

Gotchas

Field notes