skip to content

In a Wireshark capture of a slow download, which side do the TCP ZeroWindow and TCP Window Full flags each point at?

level: middleimportance: should knowfreq 17%

answer

  1. which host sent the flagged packet
  2. receiver advertising nothing free
  3. sender reaching the advertised edge
  4. probe, probe ACK, window update
  5. missing handshake, unknown scaling

basics

~20 s

TCP ZeroWindow marks the receiver's packet saying its buffer is full; TCP Window Full marks the sender's segment that reached the edge of the receiver's advertised window. Both point at the receiving side, not the network.

solid answer

~40 s

`tcp.analysis.zero_window` (a Warn) marks a packet, without SYN, FIN or RST, whose advertised window is zero: the **receiver** has no buffer free, usually because its application is not reading. You then see **TCP ZeroWindowProbe** from the sender, **ZeroWindowProbeAck** replies, and a **TCP Window Update** (Chat) when it reopens; the time from ZeroWindow to that update is the stall. `tcp.analysis.window_full` (a Warn) marks a **sender's** data segment that reaches exactly the edge of the receiver's last advertised window, so the sender must wait even though the receiver never said zero. Repeated Window Full without ZeroWindow means the advertised window itself caps throughput. If the capture missed the handshake, Wireshark shows the scaling factor as -1 (unknown), shows unscaled windows and never sets Window Full for that connection.

go deeper

for a junior

Recall that ZeroWindow comes from the receiver and Window Full from the sender, and that both point at the receiving host rather than the network.

for a middle

Explain the ZeroWindow, probe, probe ACK, window update sequence and how to time a stall, and why repeated Window Full caps throughput at window divided by RTT.

for a senior

Spot the missing-handshake trap: unknown scaling, unscaled calculated windows and no Window Full at all, and know to recapture with the handshake before ruling the window out.

for a principal

Decide where the fix belongs: receiver buffer and application read rate versus network spend, and set the expectation that captures used for this include connection setup.

## The window in one paragraph Every TCP header carries a **window** field: how many more bytes the sender of that packet is prepared to receive. The data sender may have at most that many unacknowledged bytes in flight. Why TCP works this way, and how probing keeps a closed window from deadlocking, belongs to TCP flow control; this answer is about reading Wireshark's flags for it. The two flags look alike in the Expert Info dialog but are raised on packets from **opposite ends** of the connection. ## The flags and who raises them | Info prefix | Field | Sent by | Set when | Severity | |---|---|---|---|---| | `[TCP ZeroWindow]` | `tcp.analysis.zero_window` | the data **receiver** | its advertised window is zero and SYN, FIN and RST are clear | Warn | | `[TCP Window Full]` | `tcp.analysis.window_full` | the data **sender** | a data segment ends exactly at the edge of the receiver's last advertised window | Warn | | `[TCP ZeroWindowProbe]` | `tcp.analysis.zero_window_probe` | the sender | a one-byte segment at the next expected sequence while the reverse window is zero | Note | | `[TCP Window Update]` | `tcp.analysis.window_update` | the receiver | a pure ACK whose only news is a changed, non-zero window | Chat | The zero window probe ACK (`tcp.analysis.zero_window_probe_ack`, a Note) is the receiver's reply to a probe while still advertising zero. ## Reading a ZeroWindow episode A typical stall reads like this in the packet list: 1. The receiver's ACKs advertise a shrinking window, then `[TCP ZeroWindow]`. 2. The sender stops sending data. After a pause it sends `[TCP ZeroWindowProbe]`; the receiver answers with a probe ACK still advertising zero. 3. Eventually the receiver sends `[TCP Window Update]` with a non-zero window, and data flows again. The time between step 1 and step 3 is time the transfer spent waiting **for the receiving host**, typically for its application to read the socket. The network was idle and healthy throughout. The user guide notes that a zero window is sometimes normal, for example a printer pausing a job, but usually means a performance or capacity problem on the receiving end, and resuming can take far longer than the condition that caused it. ## Reading Window Full Window Full is quieter: the receiver never says stop. The sender simply has the whole advertised window outstanding, and the segment that fills it gets the flag. When it repeats on most round trips: - the throughput ceiling is the advertised window divided by the round-trip time, whatever the link speed; - the fix is on the receiving side (a larger receive buffer, window scaling actually negotiated, an application that reads faster), not on the network path; - if `tcp.analysis.bytes_in_flight` (tracked by the **Track number of bytes in flight** preference, on by default) sits at the same value as the receiver's calculated window, you are looking at the same limit from the sender's side. Window Full together with occasional ZeroWindow says the receiver is both small and slow; Window Full without ZeroWindow says the window is the limit even though the receiver keeps up. ## The missing-handshake trap Window scaling is negotiated only in the SYN and SYN-ACK. If the capture started after the handshake, Wireshark cannot know the multiplier: - the TCP details show **Window size scaling factor: -1 (unknown)**, and **Calculated window size** shows the raw, unscaled value, which looks implausibly small; - **Window Full is never set** for that connection, because the dissector only evaluates it when the scaling is known; - ZeroWindow is still reliable, because zero times any multiplier is zero. The TCP preference **Scaling factor to use when not available from capture** (default *Not known*) changes the displayed calculated window; it does not bring Window Full back. The real fix is a capture that includes the handshake. ## Seeing it as a graph Select a packet of the slow connection and open **Statistics > TCP Stream Graphs**: - **Time Sequence (tcptrace)** draws forward segments, ACKs, SACKs, the receive window line and zero windows; data running flat against the window line is Window Full, and flat steps with zero-window marks are receiver stalls. - **Window Scaling** plots the window size against outstanding bytes, which makes a window-bound transfer obvious. ## Summary ZeroWindow: the receiver said stop. Window Full: the sender hit the receiver's limit without being told to stop. Neither is network loss, and both send you to the receiving host first.

  • The capture began mid-download and shows no Window Full flags at all, yet throughput is flat. Does that clear the receive window?
    No. Without the SYN and SYN-ACK the scaling factor is unknown (-1), and Wireshark does not evaluate Window Full for that connection, so its absence proves nothing. Recapture including the handshake, or compare bytes in flight with the window over time in the Window Scaling graph.
  • How do you measure how long a ZeroWindow stall lasted?
    Find the `[TCP ZeroWindow]` packet and the receiver's next `[TCP Window Update]` with a non-zero window in the same stream, and subtract their timestamps; setting a time reference on the first packet makes the delta direct. Several such stalls summed explain the user's wait.

saying these in an interview costs you the question

  • TCP ZeroWindow is sent by the data sender when it runs out of data.
  • Window Full means the receiver advertised a window of zero.
  • A ZeroWindow stall shows the network path is congested.
  • No Window Full flags proves the receive window is not the limit.
  • Changing the default window scaling preference makes Window Full reappear.