Articles
TCP Flow Control vs Congestion Control: Interview Questions With Packet Timelines
Practice TCP flow control vs congestion control with byte-level packet timelines, receiver windows, congestion windows, ACKs, and zero-window stalls.
A sender stops delivering data even though the network path appears healthy. A capture shows an advertised receive window of zero. In another trace, the receive window stays large, but loss recovery slows the sender. Calling both cases “TCP backpressure” hides the decision the interviewer wants you to explain.
TCP flow control protects the receiver's capacity; congestion control governs the sender's use of the network path. The receiver advertises rwnd, while the sender maintains cwnd. For a simplified established connection, new-data allowance is bounded by max(0, min(rwnd, cwnd) − bytes in flight), not by either window alone.
This article is for backend and SRE candidates. IETF standards support protocol facts; the byte ledgers and packet timelines are original synthetic exercises, not real captures or employer reports. Start with Explain OS and networking basics, then turn the verbal comparison into a concrete sender-state calculation.
Compare flow control and congestion control without mixing owners
Official: RFC 9293 specifies TCP's receive-window mechanism and acknowledgment behavior. RFC 5681 describes classic congestion-control mechanisms, including slow start, congestion avoidance, fast retransmit, and fast recovery.
Use this compact comparison:
| Question | Flow control | Congestion control |
|---|---|---|
| What problem is addressed? | Receiver-side capacity for incoming bytes | Excess load on the network path |
| Which endpoint supplies the key limit? | Receiver advertises a receive window | Sender maintains a congestion window |
| Is the limit directly advertised as a TCP window field? | Yes, with negotiated scaling where applicable | No, cwnd is sender state |
| What may stop new data? | Insufficient receive-window allowance | Insufficient congestion-window allowance |
| What is a useful next observation? | Window updates and application reads | Sender state, loss/ECN signals, and ACK behavior |
The final row is a preparation recommendation, not a claim that every implementation exposes identical diagnostics. Ask what transport algorithm and host tools are in scope before predicting a detailed cwnd trajectory.
Flow control and congestion control can constrain the same connection at different times. A slow reader can close its receive window while the sender's congestion window is large. A sender can also be congestion-limited while the receiver has ample space.
Neither window proves that the application has data ready to send. The application, pacing, send-buffer behavior, and other protocol constraints can further limit transmission. The simplified equation is an upper bound for the exercise, not a prediction that TCP immediately emits all permitted bytes.
Calculate bytes in flight before calculating new data
For the original ledger, use relative byte sequence numbers and assume no sequence wraparound, no SYN or FIN inside the trace, no SACK accounting, and in-order cumulative acknowledgments. All windows below are effective byte values after any scaling.
Let next_seq be the next new byte the sender would transmit, and acked_seq be the next byte cumulatively expected by the receiver. In this bounded model, flight = next_seq − acked_seq. A cumulative ACK releases the acknowledged bytes from this ledger.
If rwnd=6,000 bytes, cwnd=4,000 bytes, and flight=3,000 bytes, the new-data allowance is 1,000 bytes. Answering “send 4,000” forgets that 3,000 bytes already occupy the available allowance.
If the same connection's receive window becomes 2,000 bytes while flight remains 3,000 bytes, clamp new-data allowance at zero. A negative arithmetic result does not instruct TCP to “send negative bytes.” It means the simplified ledger has no allowance for additional new data at that observation.
Do not treat retransmitting an outstanding byte range as adding a second distinct copy of that range to this simple flight ledger. Retransmission and recovery accounting in an implementation is more nuanced, especially with SACK. State that distinction before applying the equation to a loss trace.
The equation also assumes the receive-window advertisement belongs to the relevant ACK context. A real TCP implementation tracks the receive-window right edge and acceptable updates. Mixing an old ACK with a newer-looking window from another direction creates a false sending limit.
Walk through a slow-reader packet timeline
Here is an original trace with a 6,000-byte receive buffer and no application reads until the final window update. Keep cwnd fixed at 4,000 bytes to isolate flow control. The initial data sequence is 1001; each labeled event describes sender state after processing that event.
| Event | Cumulative ACK | Next new sequence | Flight, bytes | Effective rwnd, bytes | New-data allowance, bytes |
|---|---|---|---|---|---|
| Before sending | 1001 | 1001 | 0 | 6000 | 4000 |
| Send bytes 1001–5000 | 1001 | 5001 | 4000 | 6000 | 0 |
| Receive ACK 3001, window 4000 | 3001 | 5001 | 2000 | 4000 | 2000 |
| Send bytes 5001–7000 | 3001 | 7001 | 4000 | 4000 | 0 |
| Receive ACK 7001, window 0 | 7001 | 7001 | 0 | 0 | 0 |
| Application drains 3000; window update arrives | 7001 | 7001 | 0 | 3000 | 3000 |
The third row acknowledges 2,000 bytes, not 3,001 bytes. An acknowledgment number denotes the next expected sequence, and the trace starts at 1001. The first send covers 4,000 bytes because both endpoints of the inclusive range are counted.
At ACK 7001, all 6,000 sent data bytes are acknowledged, but the receive buffer is still full in this exercise. The sender's flight is zero and its congestion window is unchanged. New data remains blocked because the receiver advertises no space.
The final row does not acknowledge additional data. It advertises capacity after the application drains 3,000 bytes. A window update can therefore change sending allowance without advancing the cumulative acknowledgment number.
This example exposes a common mistake: assuming every ACK means the application consumed the data. TCP receipt and application consumption are separate events. A receiver can acknowledge bytes that remain buffered while its application is stalled.
Explain what a repair targets. If the original application stopped reading because its downstream queue is full, increasing network bandwidth does not remove that queue's bottleneck. Investigate the consumer and preserve bounded buffering instead of turning a slow reader into unlimited memory growth.
Why is a zero window not the same as congestion loss?
Official: RFC 9293 describes zero-window probing so that a sender can discover that the receiver's window has reopened, including when a window update was lost. This is a different purpose from recovering an unacknowledged data segment presumed lost.
For the original slow-reader trace, the receiver may still respond to probes while advertising zero. That is evidence of an ongoing receiver-capacity stall, not proof that the network is uncongested in every respect. Keep your conclusion as narrow as the observations.
Do not describe probe traffic as an ordinary stream of newly permitted application data. Its purpose is maintaining progress information under a closed receive window. A capture containing occasional probes does not contradict the statement that normal new-data transmission is stalled.
Now change the exercise: the application drains its buffer, but the reopening update is lost. A later probe response can communicate the current window. Explain why both sides need a mechanism beyond “wait forever for the one update.”
The application still needs its own deadline and cancellation contract. Transport behavior does not decide how long an HTTP handler, upload, or message producer should keep waiting. Define what becomes retryable and whether a retry might duplicate a partially completed application operation.
Contrast a classic congestion-recovery timeline
Choose a specific algorithm before discussing numbers. This original exercise uses the classic Reno-style behavior described by RFC 5681, not every modern TCP stack or congestion algorithm.
Assume SMSS=1,000 bytes, FlightSize=8,000 bytes, and a large effective receive window of 32,000 bytes. After the qualifying duplicate-ACK pattern triggers fast recovery, the classic threshold calculation gives ssthresh=max(8,000/2, 2×1,000)=4,000 bytes.
During classic fast recovery, the congestion window is temporarily inflated to account for inferred departed packets; it is not simply fixed at “half the old window” throughout recovery. After the ACK that completes this recovery episode, use a congestion window of 4,000 bytes in the exercise.
Suppose 2,000 bytes remain in the simplified flight ledger at that point. The receive window is still 32,000, so new-data allowance is min(32,000,4,000)−2,000=2,000 bytes. Here the congestion window, not receiver capacity, is the tighter limit.
A retransmission timeout is another event with different recovery behavior. Official: RFC 6298 specifies retransmission-timer computation and backoff rules. Do not diagnose every pause as an RTO, or substitute a hardcoded timer for the actual sender's measured and maintained state.
The interview follow-up is “did three duplicate ACKs prove physical packet loss?” Not necessarily. Reordering and capture gaps complicate the evidence. Explain the sender's response under the chosen algorithm separately from a definitive diagnosis of the network's cause.
Do all congestion algorithms halve the same quantity?
No. Official: RFC 9438 specifies CUBIC, whose congestion-window evolution differs from the classic Reno exercise. Algorithm names, implementation details, and the event being processed matter when you predict window changes.
An original interview answer can say: “For this numerical trace I am using the specified classic model; for the production host I would first identify its algorithm and obtain sender-side observations.” That is more precise than treating a remembered graph as universal TCP behavior.
Official: RFC 3168 describes Explicit Congestion Notification, which can signal congestion without first dropping a packet. Consequently, a capture with no observed retransmission does not establish that congestion control was inactive.
Do not turn this distinction into an exhaustive algorithm survey. The useful goal is locating the governing limit and identifying evidence. You can explain the classic arithmetic clearly while acknowledging where a real sender requires different analysis.
What can packet capture establish about the windows?
The capture contains advertised window fields, but it does not directly carry the sender's cwnd as an ordinary TCP header field. Inferring a congestion limit from observed bursts alone is uncertain because application pacing and other limits can produce similar shapes.
Official: RFC 7323 describes negotiated window scaling. A capture starting after the handshake may lack the negotiation needed to interpret effective receive-window sizes correctly. Keep raw fields and interpreted byte values distinct.
Record capture location, direction, relevant handshake options, missing intervals, sequence and ACK numbers, and the source of any sender-state metric. A packet absent from one capture is not automatically absent from the network.
For a useful original exercise, hide the handshake and ask which numbers remain defensible. You can report the raw advertised field and observed ACK progression, but should qualify a scaled-window calculation if the scale factor is unknown.
Then compare a sender-side state sample with the packet ledger at a matching time. A host metric taken several seconds later may describe a different recovery phase. Avoid correlating a changed window with the wrong packet event merely because both appear in the same incident report.
Sources and Further Reading
Standards checked October 1, 2026. Timelines are original simplified byte models, not packet captures or claims about a particular operating system's algorithm.