Case studies — Reading TCP behavior from the packet's point of view
Triage eight cases modeled on real incident investigations in the order symptom → which promise is involved → which numbers to check. When stuck, return to the corresponding chapter and review.
The final eight — translating symptoms into "which promise is this about?"
The last chapter is pure exercise, no new lessons. You answer eight cases modeled on real incident investigations, drawing on all six chapters. When in doubt, come back to this course's motto — which promise is being broken right now: delivery, ordering, or pacing? Then translate the symptom into numbers: RST or silence? Where does the duplicate ACK's number point? Which window is taking the min?
| If you get stuck on | Go back to |
|---|---|
| IP's properties, the TCP/UDP division of labor, the 4-tuple | Chapter 1 |
| The handshake, TIME_WAIT, RST vs. FIN | Chapter 2 |
| seq/ack arithmetic, RTO, duplicate ACKs and fast retransmit | Chapter 3 |
| Window advertisements, in-flight, window ÷ RTT, zero window | Chapter 4 |
| cwnd, slow start, the two-grade response to loss | Chapter 5 |
| Byte streams, framing | Chapter 6 |
The triage map this course built. Descend in the order symptom → packet evidence → which promise is involved, and you graduate from guesswork restarts.
Case 7-1 — Cannot connect, or the connection drops
Chapters 1–2 territory. Translate each case into 'immediate refusal or silence?' and 'FIN or RST?'
Q1. Case: clients cannot connect to a freshly deployed API server. Client A gets Connection refused immediately; client B waits 30 seconds and then hits a connection timeout. Which reading of the two situations is correct?
An immediate refused is proof that an RST came back — the packet reached the host, yet nobody was listening on that port (process not started, wrong port number, and so on). A timeout after silence means no response is returning — a broken path, a downed host, or a silently dropping firewall. From A's existence you can narrow down to 'the host is alive and the port has a problem' and 'something on B's path is blocking.' Refusal after delivery versus silent non-delivery — Chapter 2's triage pattern.
Q2. Case: on a proxy server opening masses of short-lived connections to backends via a load balancer, netstat shows tens of thousands of connections in TIME_WAIT. Which understanding is correct?
TIME_WAIT is the normal state in which the side that sent the first FIN lingers, as insurance for the final ACK and to detox old segments (Chapter 2). Open and discard hundreds of short-lived connections per second, and a few dozen seconds of lingering alone yields tens of thousands. The harm is consumption of connection resources (ports and so on); the fundamental fix is reusing connections instead of reopening them every time. The right reading is not 'erase an abnormal state' but 'fix the design that mass-produces a normal one.'
Q3. Case: a long-lived database connection was killed with an RST the moment a nightly batch sent its first query in hours. Nothing abnormal happened between establishment and the idle period. What is the most likely cause?
TCP itself can hold an idle connection indefinitely (as long as both ends' ledgers remain — Chapter 2). But firewalls and NAT devices on the path keep per-4-tuple state tables and expire entries that stay idle. A segment arriving afterward becomes 'unaffiliated' and is dropped or answered with an RST. The fix is TCP keepalive or application-level heartbeats to keep looking alive. Nighttime congestion would show up first as loss and retransmissions.
Case 7-2 — Slow, or stalling
Chapters 3–5 territory. Translate into 'which kind of retransmission?' and 'which window is taking the min?'
Q4. Case: a transfer is reported slow, and the capture shows masses of ACKs with the same ack number. The receiver has received contiguously up to byte 8000; only the segment 8001–9000 was lost, and everything after it (9001 onward) keeps arriving. What is the ack number on the lined-up duplicate ACKs?
The ack number is 'the next byte wanted,' and acknowledgment is cumulative, so until the hole (8001–9000) is filled, the ack stays 8001 no matter how much later data arrives (Chapter 3). In other words, a duplicate ACK's number points directly at the first byte of the lost segment. Duplicate ACKs in a capture can be read as arrows telling you what to retransmit.
Q5. Case: file transfer to an overseas office (RTT 50 ms) over a dedicated 1 Gbps line (= 125 MB/s) reaches only 4 MB/s. Investigation finds the receiver configured with a window fixed at 200 KB (200,000 bytes). What is the throughput ceiling, in MB/s, under this setting? (1 MB = 1,000,000 bytes)
Ceiling = window ÷ RTT = 200,000 bytes ÷ 0.05 s = 4,000,000 bytes/s = 4 MB/s. It matches the observed value exactly, so the culprit is confirmed: the window setting (Chapter 4). To fill 125 MB/s of bandwidth you need a window of at least BDP = 125 MB/s × 0.05 s = 6.25 MB. For 'the line is fat but transfers are slow,' the first suspect is always window ÷ RTT.
Q6. Case: transfers to a log-collection server stall periodically. The capture shows the receiver advertising window 0 and the sender repeating small query packets. Where should you look next?
The pair zero window + window probes is the textbook capture of 'the receive buffer is full and everyone is waiting for the application to recv' (Chapter 4). The network is merely relaying the brake correctly; the culprit is a processing stall in the receiving application (slow disk writes, GC, locks, and so on). Loss or congestion would instead show retransmissions and duplicate ACKs — a different landscape from window 0.
Case 7-3 — The data looks wrong
Chapter 6 territory. Look for 'what did we assume that lies outside TCP's promises?'
Q7. Case: a service that parses JSON received from a socket throws parse errors a few times a month, only in production. The failing payloads include both JSON cut off midway and two JSON documents concatenated. What is the correct fix?
Both truncation (splitting) and concatenation (merging) appearing together is the classic symptom of the '1 recv = 1 message' assumption (Chapter 6). TCP is preserving the byte sequence and order perfectly; neither the network nor the protocol is at fault. Retrying only repeats the broken cutting. Boundaries are the application's to build — introducing framing and fixing the loop to 'accumulate, cut out, carry forward' is the only real cure.
Q8. Case: a transfer goes completely silent for several seconds, then resumes with a retransmission of the same segment, in a repeating pattern. Almost no duplicate ACKs are seen. What is happening to the sender's congestion window (cwnd) during this?
Almost no duplicate ACKs plus retransmission after silence means RTO-expiry-type retransmission, not fast retransmit (Chapter 3). TCP judges this severe, resets cwnd to 1 MSS, and starts slow start over (Chapter 5). Recovery takes many RTTs, so the user experience is 'freeze for seconds, then crawl' on repeat. Symptoms and severity both differ from the duplicate-ACK type (halve and continue) — telling the retransmission types apart is where performance readings diverge.
Closing the course — reading with the numbers' feelings
Well done. The number of facts you memorized in this course is actually tiny. What you should take with you instead is a way of reading that works in any capture and any incident log.
- Reliable delivery (noticing when it fails) — the ack is the next byte wanted. A duplicate ACK is an arrow pointing at the head of the gap. Retransmissions come in a mild type (duplicate ACK) and a severe type (RTO)
- In order — cumulative acknowledgment and the receive buffer repair disorder. But boundaries lie outside the promise — the application builds them with framing
- Paced to the peer and the network — the ceiling is min(rwnd, cwnd) ÷ RTT. A zero window means the peer is clogged; a cwnd cliff means the path is congested
If an investigation that used to stop at "some kind of timeout, let's just restart it" has turned into one that can point at which promise, in which packet, was about to be broken and how, this course has met its goal. The next time you open a capture, the columns of seq, ack, and win should read like sentences.