Sliding windows separate receiver space from path capacity
Calculate usable send credit from outstanding bytes, congestion limits, and receiver advertisements while interpreting zero-window stalls.
On this page
The question for today
What you’ll understand
- Calculate outstanding bytes and remaining send credit in a simple trace.
- Distinguish receiver flow control from network congestion control.
- Explain window scaling, zero-window probing, and application-driven stalls.
A fast sender can overwhelm a slow reader even when the network is empty. A slow network can congest even when the receiver has abundant memory. TCP maintains different limits for these different risks. Treat sending permission as a budget whose binding constraint can change over time. Then a stalled transfer becomes a question about which budget is exhausted, rather than a vague statement that the connection is slow.
Track outstanding work before spending more credit
The sender tracks a first unacknowledged position and a next position to send. Their difference, after correctly accounting for sequence wrap and recovery state, describes the outstanding stream span in a simple loss-free trace. A receiver advertisement allows a range of acceptable positions beginning at its cumulative acknowledgment. As acknowledgment advances, the left edge moves forward and older bytes stop occupying outstanding credit. Do not add every observed window advertisement together: a new advertisement describes a current window, not a new grant unrelated to all earlier grants.
For a simple steady connection outside recovery, the smaller of the congestion window and receiver window bounds outstanding data. Subtract already outstanding bytes to estimate how much new payload can be sent. This calculation also assumes the application has queued data and that pacing, local buffers, and implementation rules permit immediate transmission. A window measured in bytes is not itself a bitrate. Divide an appropriate usable flight limit by feedback time only as an approximate throughput ceiling, and then check whether application behavior or bottleneck capacity is tighter.
Receiver credit is a resource promise
Receive credit reflects data the endpoint is prepared to accept while bytes await application consumption. If the application stops reading, queued data can fill available receive space and drive the advertised window to zero. Increasing the network bandwidth cannot make that application consume its buffer. Investigate blocked readers, backpressure, memory policies, and application execution before changing congestion control. A larger receive buffer might absorb a short pause, but it can merely postpone a persistent mismatch while retaining more memory and increasing the age of queued work.
The TCP header's basic window field has sixteen bits. Window scaling negotiated during connection establishment permits larger advertised windows by applying a directional shift to later window values. The SYN's own window field is not scaled. Each direction can negotiate a different shift, so a capture must retain handshake context to decode the field correctly. Configuring large host buffers does not guarantee a correspondingly large effective advertisement; the negotiated scale, current receiver state, and implementation policy all matter. Record the effective byte count before comparing it with a path's bandwidth-delay product.
Explain a zero window without declaring the peer dead
A zero advertisement means the receiver currently offers no new ordinary receive space. TCP's zero-window probing prevents a lost window-opening update from causing an indefinite mutual wait. A responsive peer can keep advertising zero for an extended period; that behavior differs from an unreachable peer or an application-level timeout. Applications still need their own resource and deadline policies. Holding a connection forever can consume descriptors and request state even when the transport is doing its job. Log the time spent receiver-limited separately from loss recovery and application inactivity.
In the queue lab, interpret rates as normalized byte units per second and service as reader consumption. Select Reset, explicitly set both λ=3 and μ=2, predict growth from four units at t=0, then Play or Step. For a separate drain comparison, Reset again, re-set both λ=1 and μ=2, and predict zero backlog at t=4 seconds before playback. Parameter edits retain elapsed time and recompute from the initial four; they do not continue a changed-rate history. The model lacks finite receive credit and sender feedback. Its separate M/M/1 residence estimate is not an exact TCP drain time.
Work it through
Find the currently binding budget
A loss-free sender has 18,000 outstanding bytes. Its receiver window is 30,000 bytes and congestion window is 24,000 bytes. All positions are unwrapped and the application has more data.
Take the smaller window: min(30,000,24,000) is 24,000 bytes. Congestion permission is the tighter budget in this snapshot.
Subtract 18,000 outstanding bytes to obtain 6,000 bytes of estimated new credit, subject to pacing and implementation details.
If the receiver window then falls to 20,000 bytes with the same outstanding span, remaining new credit is only 2,000 bytes. The binding constraint has changed to receiver flow control.
New sending permission changes from approximately 6,000 to 2,000 bytes. The calculation does not convert either window into a physical link speed.
The living notebook
Explore the model
Interactive lab · queue
Pressure behind a receive window
Before each comparison select Reset, explicitly re-set BOTH λ and μ, predict, then Play or Step. Compare (λ,μ)=(3,2) growth with a separate (1,2) run draining from four at t=0 to zero at t=4 seconds. Parameter edits retain t and recompute the whole constant-rate curve; they do not simulate rate switching. No finite receive buffer, advertised credit, or probes are modeled.
- Fluid backlog
- 4
- Net rate · λ − μ
- −1 /s
- M/M/1 mean residence
- 1 s
Fluid backlog starts at 4 and follows max(0, 4 + (λ − μ)t). The separate M/M/1 residence-time formula assumes Poisson arrivals, exponential service and λ < μ. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forFlow control must bound the backlog when arrivals outrun consumption; a larger buffer does not remove a persistent rate mismatch.
Pause & reason
Check your understanding
Your turn
Try it yourself
A post-handshake window field is 4,000 with negotiated shift 5. At RTT 0.04 seconds, calculate the effective window and its rough window-limited throughput ceiling.
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Scale by a power of two, then divide bytes by seconds. Keep bits and bytes separate.
Compare with the solution
The effective window is 4,000 × 32 = 128,000 bytes. Dividing by 0.04 seconds gives approximately 3,200,000 bytes per second, or 25.6 million bits per second. This is only a window ceiling under the stated assumptions; congestion, application supply, pacing, and link overhead can reduce throughput.
Keep the idea
Take it with you
- Receive windows protect endpoint capacity; congestion windows protect network paths.
- Outstanding bytes consume credit that cannot be counted again as new permission.
- A zero window can expose slow application consumption rather than network failure.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.