What is silly window syndrome in TCP, and how do the sender and the receiver each avoid it?
answer
- tiny window, tiny segments, forever
- slow reader or dribbling writer
- advertise in MSS-sized steps
- send full segments or half the window
basics
~20 sSilly window syndrome is a stable TCP pattern of tiny window openings filled by tiny segments. RFC 9293 requires both sides to avoid it: receivers withhold small window increases, senders wait for a worthwhile amount to send.
solid answer
~50 s**Silly window syndrome** (SWS, RFC 813; RFC 9293 §3.8.6.2) happens when the right edge of the window advances in small steps: a receiver whose application reads a few bytes at a time advertises each small opening, and a sender fills each opening with a tiny segment, so the connection settles into sending tiny segments with large header overhead. RFC 9293 makes avoidance mandatory on both sides. The **receiver** keeps the window's right edge fixed until the freed space reaches `min(RCV.BUFF/2, MSS)` (using the recommended fraction 1/2), so it opens in roughly MSS-sized steps. The **sender** sends only a full segment, or at least half the largest window it has seen, or all its pushed data when nothing is outstanding, with an override timer of 0.1-1.0 s. Nagle's algorithm is its complement for data arriving in small increments.
code
pseudocode · 6 lines# receiver: decide whether to open the advertised window
free_unadvertised = RCV_BUFF - RCV_USER - RCV_WND
if free_unadvertised >= min(RCV_BUFF / 2, EFF_SND_MSS):
RCV_WND = RCV_BUFF - RCV_USER # open in one worthwhile step
else:
keep RCV_NXT + RCV_WND fixed # withhold the small increasego deeper
Remember the picture: tiny window openings filled by tiny segments, over and over, with header overhead dwarfing the data.
Explain both halves: the receiver opens its window only in about MSS-sized steps, the sender sends only worthwhile segments, and both are mandatory in RFC 9293.
Connect it to observed behaviour: a slow consumer produces windows that close and reopen in MSS-sized jumps, and runt segments point at an application or stack that ignores these rules.
Use SWS as the reason transport APIs favour bulk reads and writes; designs that read or write a few bytes at a time push work onto every stack in the path.
## What goes wrong TCP's receiver advertises a **window**: how many more bytes it can accept beyond what it has acknowledged. The sender may send up to that edge. Nothing in the basic mechanism says a window change or a segment has to be large, and David Clark's RFC 813 (1982) showed what follows. RFC 9293 §3.8.6.2 defines the result: **Silly Window Syndrome (SWS)** is a *stable pattern of small incremental window movements resulting in extremely poor TCP performance*. The pattern can start from either end: - **Receiver-side cause**: the receiving application consumes data a few bytes at a time. Each time it frees a few bytes, the receiver advertises a slightly larger window. - **Sender-side cause**: the sender transmits as soon as any usable window exists, or its application produces data in small pieces. Once a small segment fills a small opening, the next opening is small too, and the connection keeps sending segments carrying a few bytes of data each under 40 or more bytes of headers. Unlike a transient burst, the pattern is **self-sustaining**, which is why both sides must actively break it. ## The receiver's rule RFC 9293 says a TCP implementation **MUST** include SWS avoidance in the receiver (MUST-39). The idea is to avoid advancing the right window edge (`RCV.NXT + RCV.WND`) in small increments, even when data arrives in small segments. The receive buffer `RCV.BUFF` is split into data received but not yet consumed (`RCV.USER`), the advertised window (`RCV.WND`), and a **reduction**: space that is free but not yet advertised. The receiver keeps the right edge fixed until: ``` RCV.BUFF - RCV.USER - RCV.WND >= min( Fr * RCV.BUFF, Eff.snd.MSS ) Fr = 1/2 ``` Then it sets `RCV.WND = RCV.BUFF - RCV.USER` in one step. With realistic buffers the window therefore opens in increments of about one MSS. This rule works together with **delayed ACK**, which decides when an ACK carrying the updated window is actually sent. ## The sender's rule RFC 9293 also says a TCP implementation **MUST** include SWS avoidance in the sender (MUST-38). The sender cannot see the receiver's buffer size, so it uses `Max(SND.WND)`, the largest window it has seen on the connection, as an estimate. With `U` the usable window (`SND.UNA + SND.WND - SND.NXT`) and `D` the data queued to send, it sends when: 1. a **maximum-sized segment** can be sent: `min(D, U) >= Eff.snd.MSS`; 2. or the data is **pushed** and all queued data fits (`D <= U`), with nothing outstanding when Nagle is in use; 3. or at least a fraction **Fs = 1/2** of the maximum window can be sent (again with nothing outstanding under Nagle); 4. or an **override timeout** fires, recommended in the range **0.1-1.0 seconds**. The override timer exists because `Max(SND.WND)` is only an estimate: the receiver may shrink its buffer, and without the timer the sender could wait forever for a window that will never be large enough. ## How it relates to Nagle | Mechanism | Side | What arrives in small increments | Rule | |---|---|---|---| | Nagle's algorithm | sender | application data | hold small data while data is unacknowledged | | Sender SWS avoidance | sender | the usable window | send only full segments, half the max window, or pushed data | | Receiver SWS avoidance | receiver | freed buffer space | advertise only MSS-sized (or half-buffer) increases | | Delayed ACK | receiver | incoming segments | acknowledge fewer than one per segment, within 0.5 s | RFC 9293 calls Nagle and sender SWS avoidance **complementary**: Nagle discourages tiny segments when the data grows in small increments, while SWS avoidance discourages them when the **window edge** grows in small increments. ## Why it matters today Every conforming stack implements both halves, so SWS is rarely seen on the wire; the question tests whether a candidate understands why TCP does not simply send whatever the window allows. It still explains behaviours engineers notice: behind a slow-reading consumer the advertised window reopens in MSS-sized jumps rather than byte by byte, and a sender with a little data and a little window may wait briefly rather than send a runt segment.
- Why does the TCP sender's SWS avoidance need an override timer?The sender cannot see the receiver's buffer, so it estimates it from the largest window seen, `Max(SND.WND)`. If the receiver shrinks its buffer, the rule 'send at least half the maximum window' may never be met, and the sender would wait forever. RFC 9293 recommends an override timeout of 0.1-1.0 seconds to force transmission.
- Is silly window syndrome the same thing as a zero window in TCP?No. A zero window means the receiver has no space and the sender must stop, probing until space opens. SWS is about windows that are open but only by tiny amounts, leading to a stream of tiny segments; avoidance works by refusing to advertise or use those tiny openings.
saying these in an interview costs you the question
- Silly window syndrome is fixed by making the receive buffer larger.
- Only the sender needs an SWS avoidance algorithm.
- Silly window syndrome is the same thing as a zero-window stall.
- Nagle's algorithm is the receiver's defence against silly window syndrome.
- The receiver should advertise every byte of freed space immediately.