TCP has two different reasons to limit how much data can be in flight. Flow control protects the receiver from being overwhelmed; congestion control protects the network from overload. The receiver advertises a receive window (rwnd), while the sender also maintains a congestion window (cwnd). The amount of outstanding data is constrained by both.
Remember the shape, not the sentence
“One limiter is the size of the receiving warehouse; the other is the traffic jam on the road. A huge warehouse does not make it wise to keep sending into a congested highway.”
Flow control
The receiver advertises available buffer space. If the receiver cannot keep up, the sender must slow down even when the network itself is healthy.
Congestion control
The sender infers network capacity from acknowledgements and loss/ECN signals. Slow start probes capacity rapidly, while congestion avoidance grows more cautiously.
The effective window
A simplified mental model is send_window ≈ min(rwnd, cwnd). Real TCP behavior includes many additional limits and algorithms, but this minimum is the crucial conceptual anchor.
See the mechanism before you memorize it
One diagram, one causal story, one reconstruction task.
Flow control (rwnd) vs congestion control (cwnd, slow start) — causal map
Receiver
Advertises rwnd based on available receive buffer.
Sender
Tracks cwnd based on congestion-control state.
In flight
Outstanding bytes cannot exceed the effective sending window.
Feedback
ACK progress, loss and ECN-like signals update the control state.
Draw the idea yourself
Rebuild the core flow on a real canvas before moving to the worked walkthrough.
Walk the system
Receiver
Advertises rwnd based on available receive buffer.
Sender
Tracks cwnd based on congestion-control state.
In flight
Outstanding bytes cannot exceed the effective sending window.
Feedback
ACK progress, loss and ECN-like signals update the control state.
Adapt
The sender grows, holds or reduces its sending rate.
Core relationship
Keep the two causes separate in your head. A slow receiver and a congested network are not the same problem.
effective_window = min(rwnd, cwnd)
slow start: rapid probing
congestion avoidance: cautious growth
loss/congestion signal: reduce sending rateWhat usually goes wrong
Close the tab. Rebuild it from memory.
Read the question, answer aloud, then reveal.
Who controls rwnd?Reveal answer
The receiver, based on available receive buffer capacity.
Who controls cwnd?Reveal answer
The sender's congestion-control algorithm, using network feedback.
Why is min(rwnd, cwnd) useful?Reveal answer
It reminds you that either the receiver or the network can be the current bottleneck.
Make this idea travel.
Connect it next to: udp-quic • tcp-packet-analysis • dns.