Both TCP and UDP sit at Layer 4 and both use port numbers to reach the right application — but they make almost opposite tradeoffs to get there. TCP spends effort guaranteeing delivery; UDP spends none, and hands that job to whoever's using it.
| Property | TCP | UDP |
|---|---|---|
| Connection | Connection-oriented — three-way handshake required | Connectionless — just send |
| Reliability | Guaranteed delivery via acknowledgment and retransmission | No guarantee — a lost datagram simply vanishes |
| Ordering | Guaranteed in-order delivery to the application | No ordering guarantee |
| Flow control | Sliding window (demo below) | None |
| Congestion control | Yes — backs off automatically when the network is overloaded | None — the application must self-limit |
| Header overhead | 20+ bytes | 8 bytes |
| Typical uses | Web (HTTP), email, file transfer, SSH | DNS queries, voice/video calls, gaming, live streaming |
A receiver only has so much buffer space. Its receive window tells the sender exactly how many unacknowledged segments it can have in flight at once. Every time an ACK arrives, the window slides forward by one, making room to send the next segment. Try sliding the window yourself:
Beyond the receiver's window, TCP also tracks its own estimate of how much the network can handle: the congestion window (cwnd). It starts small and grows — fast at first, then cautiously — until a loss tells it to back off. Repeated over time this produces TCP's famous sawtooth shape:
Hover the chart to read exact values. Why it looks like this: growing exponentially (slow start) would risk overshooting the network's real capacity, so TCP switches to a cautious linear climb (congestion avoidance) once it's in roughly the right range — then treats any loss as a signal it pushed too far, and cuts back hard before climbing again.