TCP and UDP/TCP, step by step/Congestion: the crowded desks
Lesson 9 of 12 · in 3D and VR

Congestion: the crowded desks

Nobody tells a TCP sender how much a path can carry, so it finds out. It starts small, grows until a segment is dropped, then cuts its window and grows again. Real stacks differ in the details. That limit is separate from the receiver's window, and whichever is smaller rules.

Lonely BinaryUpdated 2026-10-015 min readNo board required

View it in VR

Lesson 9 of the TCP and UDP course opens in a VR headset, on a table in front of you, and a voice starts three seconds after you arrive. Type this short address into the browser on a headset such as Meta Quest or Apple Vision Pro, and press Enter VR. No headset? Press Start the lesson: the same lesson, full screen.

learn.lonelybinary.com/vr/tcp-udp/9

A router forwards what it is handed, and when more arrives than it can pass, it keeps the rest in a queue. The queue is finite. When it is full, the next segment is dropped, and nothing tells the sender. In October 1986 the data rate from Lawrence Berkeley Laboratory to UC Berkeley, two sites 400 yards and two hops apart, fell from 32 kbit/s to 40 bit/s. Van Jacobson and Michael Karels described slow start and congestion avoidance in a paper presented at SIGCOMM in 1988, and both are in the standard today as RFC 5681.

Two limits

The receiver's window protects the receiver. A second number, kept only by the sender, protects the path: the congestion window, written cwnd. The sender may have in flight only the smaller of the two. Most of the time one of them is the limit and the other has room to spare, and which one it is can change from one round trip to the next.

Start small

A new connection does not know the path, so it starts with a small cwnd. While cwnd is below a threshold, each acknowledgement that arrives lets it send one more segment, which doubles the window every round trip. This is slow start. The name is for the starting point, not for the pace. Past the threshold, congestion avoidance adds one segment per round trip. The standard starts the threshold arbitrarily high, and the bench stops slow start at eight strips so that one run shows both phases.

How small is small? The standard allows an initial window of up to four small segments, three at Ethernet size. RFC 6928 proposes ten, but it is Experimental, and Linux uses ten without that making it the standard. lwIP on the ESP32 starts with 4380 bytes, about three segments. The bench starts with two.

Loss is the signal

When a tray overflows, a strip is lost, and the sender finds out as in lesson 7: repeated acknowledgements or a timer. Either one tells it the path is full. Three repeated acknowledgements make it halve its window, resend and carry on. A timeout is taken more seriously, and in the bench it sends the window back to one strip. Then slow start begins again, up to half the old window, and the one-segment-per-round-trip climb follows.

Several senders do the same thing without talking to each other. Each one grows until it sees loss and then cuts. Together they tend to settle near what the narrowest desk can carry, and nobody was told what that is.

Loss is not always congestion

TCP treats a lost segment as a sign of a crowded network, even when a radio dropped it. A radio can drop a segment while every queue is empty, and TCP reads that as a crowded network all the same. Loss is the classic signal and not the only one. ECN lets a router mark a segment to say slow down, instead of dropping it. And the bench is a teaching model: its tray is four strips deep, its timer is a fixed count, and real stacks differ in the details.

Common mistakes

  • Blaming the receiver's buffer for a slow start. A new connection starts small by design, whatever buffers either side has.
  • Reading every loss as a bad link. Some of it is the sender's own growth meeting a full tray.
  • Expecting a faster retry to help a full path. More segments into a full tray only add to the drops, which is why each timeout waits longer than the last.

Edit this page — content/fundamentals/tcp-udp/congestion.mdx

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Fundamentals on the forum →