Flow control stops a fast sender from burying a slow reader, using one number the receiver puts in every segment — and it has one genuinely awkward corner.
Words you will meet
- Flow control — matching the sender’s rate to the rate the receiving application reads.
RcvBuffer— the size of the receive buffer.rwnd— the receive window: how much spare room is left in it.- Speed-matching service — the book’s name for what flow control is.
Why this matters
Everything so far has assumed the receiver keeps up. It often does not. The receiving application may be busy with something else entirely, and may not read its data until long after it arrives. A sender that keeps sending will then overflow the buffer and destroy data that arrived perfectly.
This is also the section where two ideas that look identical must be kept apart. Flow control and congestion control both throttle the sender, and the book warns in as many words that many authors use the terms interchangeably. The savvy reader distinguishes them, and sections 3.6 and 3.7 will be much harder if you do not.
A speed-matching service
Flow control flow control Simple Stopping a fast sender from filling up a slow reader’s buffer. Precise A speed-matching service that matches the rate at which the sender sends against the rate at which the receiving application reads. It protects the *receiver*, and is easy to confuse with congestion control, which protects the *network*. Both throttle the sender, for entirely different reasons. UDP has no flow control, so its segments are simply dropped when the receiving buffer overflows. introduced in ch. 3 — open in glossary eliminates the possibility of the sender overflowing the receiver’s buffer. The book’s phrase for it is exact — a speed-matching service. It matches the rate at which the sender is sending against the rate at which the receiving application is reading.
Not against the rate the network can carry. Not against the rate the receiver’s TCP (Transmission Control Protocol) Transmission Control Protocol The Internet transport protocol that delivers data reliably and in order, with flow control and congestion control. introduced in ch. 1 can process. Against the rate the application reads.
Before any data arrives, LastByteRcvd equals LastByteRead and the buffer is empty. Host B sets rwnd = RcvBuffer and advertises it.
Two pointers and a subtraction. Step through a slow reader filling the buffer up.
Read all steps as text
- 1 — Empty, and the whole buffer is offered — Before any data arrives, LastByteRcvd equals LastByteRead and the buffer is empty. Host B sets rwnd = RcvBuffer and advertises it.
- 2 — Data arrives and the application keeps up — Bytes land in the buffer and the application reads them out at about the same rate. The gap between the two pointers stays small, so rwnd stays large and the sender is never held back.
- 3 — The application slows down — The receiving application is busy with something else. Data keeps arriving; nobody is reading it. LastByteRcvd runs ahead of LastByteRead and the gap widens.
- 4 — Full. rwnd = 0. — The buffer is completely occupied by unread data. B advertises rwnd = 0, and Host A must stop sending. Nothing has gone wrong — the receiver is simply busy, and TCP has matched the sender to it.
- 5 — The sender keeps its side of the bargain — Host A tracks LastByteSent and LastByteAcked. It keeps LastByteSent − LastByteAcked ≤ rwnd, so it can never put more unacknowledged data into the network than B has room for. That inequality is the whole of flow control.
Four variables, one subtraction
At the receiver, Host B:
LastByteRead— the last byte the application has read out of the buffer.LastByteRcvd— the last byte that has arrived from the network and gone in.
TCP must never overflow the buffer, so LastByteRcvd − LastByteRead ≤ RcvBuffer.
The receive window receive window Simple A number the receiver puts in every segment saying how much free buffer space is left. Precise rwnd = RcvBuffer − [LastByteRcvd − LastByteRead]: the spare room in the receive buffer, advertised in the 16-bit receive-window field of every segment. The sender keeps LastByteSent − LastByteAcked ≤ rwnd. When rwnd reaches 0 the sender must keep sending one-byte segments, or it would never learn that space had opened up again.
introduced in ch. 3 — open in glossary
is whatever is left over:
Because the spare room changes constantly, rwnd is dynamic. B puts its
current value in the receive-window field of every segment it sends to A, and
sets it to RcvBuffer at the start.
At the sender, Host A keeps LastByteSent and LastByteAcked. Their
difference is the amount of unacknowledged data A has put into the network, and
A’s whole obligation is:
What each symbol means
- RcvBuffer — the size of the receive buffer (bytes)
- LastByteRcvd — the last byte that has arrived from the network (byte number)
- LastByteRead — the last byte the application has read out (byte number)
- rwnd — spare room, advertised in every segment (bytes)
Read aloud: Take the size of the buffer and subtract what is sitting in it unread. What is left is how much more the sender may send.
rwnd2,596 bytes
the buffer is holding LastByteRcvd − LastByteRead = 3,000 − 1,500 = 1,500 bytes
rwnd = RcvBuffer − [LastByteRcvd − LastByteRead]
= 4,096 − 1,500
= 2,596 bytes of spare room
the sender must keep LastByteSent − LastByteAcked ≤ 2,596
this fits in the 16-bit receive-window fieldChange any number above and the arithmetic re-runs, carrying the units through.
Now drag LastByteRead down towards LastByteRcvd — a slow application — and watch rwnd reach zero. That is where the interesting problem starts.
A simplification the book makes here, worth noticing
This section assumes “the TCP receiver discards out-of-order segments”, so that the reader can see the forest for the trees.
That is worth flagging, because section 3.5.4 said the opposite about real implementations: the RFCs leave the choice open and practice is to buffer out-of-order segments.
Both statements are fine — this one is an explicit simplifying assumption, not a claim about reality. But it does mean the buffer arithmetic above is slightly tidier than the real thing, where the receiver may also be holding segments above a gap.
The awkward corner
Now the problem, and it is a real deadlock rather than a slowdown.
Suppose B’s receive buffer fills, so it advertises rwnd = 0. Host A stops sending, exactly as instructed. Suppose also that B has nothing of its own to send to A.
Then the application at B drains the buffer. Room reopens. And nobody tells A.
Nothing is lost, nothing is corrupted, and neither host does anything wrong. The connection stops anyway.
Click any arrow to see what that message says and why it is sent.
Switch between the two runs. In the first, both hosts are behaving correctly and the connection stops forever.
Read this diagram as text
- Host A sends data to Host B.
- Host B sends ACK, rwnd = 0 to Host A. The buffer is full. B advertises a window of zero, which A must obey. B has no data of its own to send.
- Host B sends (the application drains the buffer — but B sends nothing) to Host A — lost. Here is the trap. TCP sends a segment only when it has data to send or an acknowledgement to send. B now has neither: A has stopped sending, so there is nothing to acknowledge. The window update that A is waiting for never leaves.
Lifelines, left to right: Host A (host), Host B (server).
In plain words
TCP sends a segment only when it has data to send or an acknowledgement to send.
With rwnd = 0, A has stopped sending. So B receives nothing, so B has nothing to acknowledge, so B sends nothing. A is never told the receive window reopened. The silence sustains itself, and neither host is doing anything wrong.
The specification’s fix puts the burden on the sender. A must continue to send segments with one data byte while B’s receive window is zero. Those segments are acknowledged, and eventually one of those acknowledgements carries a non-zero rwnd.
One byte, because it is the smallest thing that obliges a reply.
The ceiling nobody mentions until it hurts
Section 3.4.2 worked out that Lin’s path — 100 Mbps, 180 ms — needs about 2.25 megabytes in flight to keep the link busy.
Section 3.5.2 showed that the receive-window field is 16 bits.
What each symbol means
- window — the most that may be outstanding at once (bytes)
- RTT — round-trip time (s)
Read aloud: A sender may have only one window of data unacknowledged at a time, so it can never send more than one window per round trip — whatever the link could carry.
Fastest this connection can go2.91 Mbps
at most one window may be outstanding per round trip
so throughput ≤ window / RTT = 65,535 bytes × 8 / 180 ms
= 2.91 Mbps
the link itself can carry 100 Mbps, so the window is using 2.91 % of it
to fill this path the window would need the bandwidth-delay product: 100 Mbps × 180 ms / 8 = 2,250,000 bytes
that is beyond the 16-bit field, so the window scale option must multiply it by 2^6Change any number above and the arithmetic re-runs, carrying the units through.
The defaults are the largest window a 16-bit field can advertise, on Lin’s path. Compare the answer with the 100 Mbps the link actually offers.
65,535 bytes is about 45 segments, and about 2.9 Mbps
A sender may have at most one receive window of unacknowledged data outstanding, so it can never send more than one window per round trip. On Lin’s path that caps the connection at
on a link that can carry a hundred. Under 3 % of it, and no amount of congestion-window growth in section 3.7.1 can get past it, because the sender obeys the smaller of the two windows.
This is what the window scale option in RFC (Request For Comments) Request For Comments The name of an IETF standards document. There are currently nearly 9000 of them. introduced in ch. 1 7323 is for. It multiplies the advertised value by a power of two agreed during the handshake. To reach 2.25 MB the scale factor must be 2⁶, giving a maximum of about 4.19 MB.
The book mentions “a window scaling factor for use in high-speed networks” in section 3.5.2 and never puts a number on it. This is the number.
Keeping the two apart
| Flow controlthis section | Congestion controlsections 3.6 and 3.7 | |
|---|---|---|
| Protects | ||
| From | ||
| The sender learns the limit | ||
| Variable | ||
| Where it is kept | ||
| Does UDP have it? |
Cells marked ⓘ have a reason behind them — click to read it.
The book warns that many authors use these interchangeably. They are not interchangeable, and this grid is why.
And UDP (User Datagram Protocol) User Datagram Protocol A simple transport protocol with no reliability, no flow control and no congestion control. introduced in ch. 1 has none of this
UDP provides no flow control, so its segments may be lost at the receiver through buffer overflow.
A typical UDP implementation appends arriving segments to a finite buffer that sits in front of the socket. The process reads one entire segment at a time from that buffer. If it does not read fast enough, the buffer overflows and segments are dropped.
Silently. The sender is not told, and neither is the receiving application. From the outside it is indistinguishable from loss in the network — which, from section 3.3, UDP also does nothing about.
Check yourself
Check yourself
0 of 6 answered1.Flow control and congestion control both slow the sender down. What is the difference?
Ask who is being protected in each case.
2.predictSet the calculator to a 4,096-byte buffer with LastByteRcvd 3,000 and LastByteRead 1,500. What is rwnd?
3.Host B advertises rwnd = 0 and has no data of its own to send. Its application then drains the buffer. What goes wrong?
4.How does TCP break that deadlock?
5.predictSet the ceiling calculator to a 65,535-byte window on Lin's 100 Mbps, 180 ms path. What is the fastest the connection can go?
Only one window may be outstanding per round trip.
6.What happens when a UDP receiver's buffer overflows?
What to remember
- Flow control is a speed-matching service: the sender’s rate against the rate the application reads, not the network’s rate.
- rwnd = 0 would deadlock, because a silent receiver has nothing to acknowledge and so never sends the update. The sender must keep probing with one-byte segments.
- Flow control is not congestion control. One protects the receiver and is told the limit explicitly; the other protects the network and must infer it. UDP has neither, and overflows silently.