TCP Flow & Congestion Control
IntermediateTCP flow control prevents the sender from overwhelming the receiver; congestion control prevents the sender from overwhelming the network — both use sliding windows to regulate data rate.
Overview
TCP guarantees reliable delivery but must also be a good citizen on the network. Two mechanisms keep it in check. Flow control uses the receiver's advertised window (rwnd) to tell the sender how much buffer space is available — the sender never sends more than rwnd bytes ahead of acknowledgement. Congestion control uses a separate congestion window (cwnd) maintained by the sender, grown aggressively at first (slow start) then carefully (congestion avoidance), and shrunk on packet loss. The actual send rate is min(rwnd, cwnd). Algorithms like TCP Reno, CUBIC, and BBR differ in how they grow cwnd and respond to loss. For backend engineers, understanding these mechanisms explains why a single TCP connection underutilises high-bandwidth long-latency links (bandwidth-delay product problem) and why file-transfer optimisation requires tuning TCP buffers.
Flow Control — Receiver Window
The receiver advertises its available buffer size in the rwnd field of every ACK. If the receiver's application is slow to consume data, rwnd shrinks, slowing the sender. This creates back-pressure from application layer all the way to the network.
// Flow control: receiver advertises window in every ACK
//
// Sender Receiver (rwnd = 64KB)
// │──── 1KB data ─────────────────>│ rwnd: 64→63KB in ACK
// │──── 1KB data ─────────────────>│ rwnd: 63→62KB in ACK
// │ ... (sends up to rwnd) ──────>│
// │<─── ACK, rwnd=0 ───────────────│ Receiver buffer full! App slow to read
// │ (sender blocks — zero window) │
// │──── ZWP (Zero Window Probe) ──>│ Sender probes periodically
// │<─── ACK, rwnd=32KB ────────────│ Receiver freed buffer space
// │ (sender resumes) ─────────────│
// Java — increase socket receive buffer to reduce flow control stalls:
Socket socket = new Socket();
socket.setReceiveBufferSize(256 * 1024); // 256KB receive buffer
socket.setSendBufferSize(256 * 1024); // 256KB send buffer
// For high-throughput servers, tune OS-level TCP buffers:
// Linux: sysctl -w net.core.rmem_max=16777216
// sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216"Congestion Control — Slow Start & AIMD
Congestion control prevents a single sender from flooding the network. TCP starts with a small congestion window (cwnd=1 MSS) and grows exponentially (slow start) until it hits ssthresh or detects loss. After that, it grows linearly (congestion avoidance — Additive Increase). On loss, it halves cwnd (Multiplicative Decrease). This AIMD behaviour is what makes TCP "fair" — competing flows converge to equal shares.
// Congestion control phases:
//
// Slow Start (cwnd grows exponentially):
// RTT 1: cwnd=1 MSS → send 1 segment
// RTT 2: cwnd=2 MSS → send 2 segments
// RTT 3: cwnd=4 MSS → send 4 segments
// ... doubles every RTT until cwnd reaches ssthresh
// Congestion Avoidance (cwnd grows linearly):
// cwnd += 1 MSS per RTT (one segment per window)
// On packet loss (timeout):
// ssthresh = cwnd / 2
// cwnd = 1 MSS (restart slow start)
// On triple duplicate ACK (fast retransmit):
// ssthresh = cwnd / 2
// cwnd = ssthresh (skip slow start — TCP Reno/CUBIC)
// TCP algorithms:
// Reno — classic AIMD, reduces cwnd by half on loss
// CUBIC — dominant in Linux; uses cubic function, better on high-BDP links
// BBR — Google's; models bandwidth & RTT, not just loss — better for cloud
// Check active algorithm:
// sysctl net.ipv4.tcp_congestion_control → usually 'cubic' or 'bbr'Key Points to Remember
- 1Flow control: receiver advertises rwnd; sender cannot exceed it. Protects receiver buffer.
- 2Congestion control: sender maintains cwnd. Protects the network.
- 3Actual send rate = min(rwnd, cwnd).
- 4Slow start: cwnd doubles per RTT. Congestion avoidance: cwnd increases by 1 MSS per RTT.
- 5On loss: cwnd is halved (AIMD). On timeout: cwnd resets to 1 (full slow start).
- 6BBR (Google) is bandwidth-based, not loss-based — performs better on high-latency links.
Interview Questions
Sign in to ask AriaWhat is the difference between flow control and congestion control in TCP?
Explain TCP slow start and congestion avoidance.
Why does a single TCP connection underperform on a high-bandwidth, high-latency link?
What is the difference between TCP Reno and BBR?
What happens when a TCP receiver advertises a zero window?
Ask Aria about TCP Flow & Congestion Control
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.