Two Wireshark labs rebuilt as captures you can click through, one of them containing a real lost segment and its recovery. Then the reliable-transfer programming assignment in both its versions, and four questions to the man who worked out why 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 was collapsing.
What is on this page
- Wireshark Lab: Exploring TCP — a file uploaded, a segment lost, three duplicate acknowledgements and a fast retransmit, all in 28 packets.
- Wireshark Lab: Exploring 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 — the four header fields, and the checksum arithmetic done word by word so you can check it.
- The rdt programming assignment — working Python for both versions the book offers: alternating-bit and Go-Back-N.
- An interview with Van Jacobson, who found TCP’s congestion control by asking a different question.
Why this matters
Everything in this chapter was a mechanism described in words and diagrams. A packet capture is where you learn whether you believed it.
The TCP capture below is the useful one. Its middle contains the single most important sequence in the chapter. A segment vanishes, the receiver keeps asking for the same byte, and after the third repeat the sender resends. No timer expires. If you can point at those packets and say which is which, you understand section 3.5.4.
The 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 capture is here for the opposite reason. It is four header fields and eighteen bytes, and it takes about a minute. That is the comparison.
Wireshark Lab: Exploring TCP
The book’s lab uploads a file to a Web server with an HTTP (HyperText Transfer Protocol) HyperText Transfer Protocol The application-layer protocol that requests and transfers Web documents. introduced in ch. 1 POST. It then asks you to trace TCP’s window behaviour, and to infer loss, retransmission, flow control and congestion control from the trace. This capture is that upload: 12,620 bytes in nine segments, captured at the sender.
Capturing at the sender matters. Packet 11 never arrives anywhere. It is in the trace because the client transmitted it, and the client will not learn otherwise for another 120 milliseconds.
| No. | Time | Source | Destination | Protocol | Length | Info |
|---|---|---|---|---|---|---|
| 1 | 0.000000 | 192.168.1.24 | 198.51.100.7 | TCP | 58 | 52310 → 80 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 |
| 2 | 0.060200 | 198.51.100.7 | 192.168.1.24 | TCP | 58 | 80 → 52310 [SYN, ACK] Seq=0 Ack=1 Win=64240 Len=0 MSS=1460 |
| 3 | 0.060250 | 192.168.1.24 | 198.51.100.7 | TCP | 54 | 52310 → 80 [ACK] Seq=1 Ack=1 Win=64240 Len=0 |
| 4 | 0.060330 | 192.168.1.24 | 198.51.100.7 | TCP | 1514 | 52310 → 80 [PSH, ACK] Seq=1 Ack=1 Win=64240 Len=1460 |
| 5 | 0.120530 | 198.51.100.7 | 192.168.1.24 | TCP | 54 | 80 → 52310 [ACK] Seq=1 Ack=1461 Win=64240 Len=0 |
| 6 | 0.120580 | 192.168.1.24 | 198.51.100.7 | TCP | 1514 | 52310 → 80 [ACK] Seq=1461 Ack=1 Win=64240 Len=1460 |
| 7 | 0.121790 | 192.168.1.24 | 198.51.100.7 | TCP | 1514 | 52310 → 80 [ACK] Seq=2921 Ack=1 Win=64240 Len=1460 |
| 8 | 0.180780 | 198.51.100.7 | 192.168.1.24 | TCP | 54 | 80 → 52310 [ACK] Seq=1 Ack=2921 Win=64240 Len=0 |
| 9 | 0.180830 | 198.51.100.7 | 192.168.1.24 | TCP | 54 | 80 → 52310 [ACK] Seq=1 Ack=4381 Win=64240 Len=0 |
| 10 | 0.180880 | 192.168.1.24 | 198.51.100.7 | TCP | 1514 | 52310 → 80 [ACK] Seq=4381 Ack=1 Win=64240 Len=1460 |
| 11 | 0.182090 | 192.168.1.24 | 198.51.100.7 | TCP | 1514 | 52310 → 80 [ACK] Seq=5841 Ack=1 Win=64240 Len=1460 ← lost in the network |
| 12 | 0.183300 | 192.168.1.24 | 198.51.100.7 | TCP | 1514 | 52310 → 80 [ACK] Seq=7301 Ack=1 Win=64240 Len=1460 |
| 13 | 0.184510 | 192.168.1.24 | 198.51.100.7 | TCP | 1514 | 52310 → 80 [ACK] Seq=8761 Ack=1 Win=64240 Len=1460 |
| 14 | 0.241080 | 198.51.100.7 | 192.168.1.24 | TCP | 54 | 80 → 52310 [ACK] Seq=1 Ack=5841 Win=64240 Len=0 |
| 15 | 0.241130 | 192.168.1.24 | 198.51.100.7 | TCP | 1514 | 52310 → 80 [ACK] Seq=10221 Ack=1 Win=64240 Len=1460 |
| 16 | 0.241180 | 198.51.100.7 | 192.168.1.24 | TCP | 54 | 80 → 52310 [ACK] Seq=1 Ack=5841 Win=62780 Len=0 [TCP Dup ACK 1] |
| 17 | 0.241230 | 198.51.100.7 | 192.168.1.24 | TCP | 54 | 80 → 52310 [ACK] Seq=1 Ack=5841 Win=61320 Len=0 [TCP Dup ACK 2] |
| 18 | 0.301330 | 198.51.100.7 | 192.168.1.24 | TCP | 54 | 80 → 52310 [ACK] Seq=1 Ack=5841 Win=59860 Len=0 [TCP Dup ACK 3] |
| 19 | 0.301390 | 192.168.1.24 | 198.51.100.7 | TCP | 1514 | 52310 → 80 [PSH, ACK] Seq=5841 Ack=1 Win=64240 Len=1460 [TCP Fast Retransmission] |
| 20 | 0.361590 | 198.51.100.7 | 192.168.1.24 | TCP | 54 | 80 → 52310 [ACK] Seq=1 Ack=11681 Win=64240 Len=0 |
| 21 | 0.361640 | 192.168.1.24 | 198.51.100.7 | TCP | 994 | 52310 → 80 [PSH, ACK] Seq=11681 Ack=1 Win=64240 Len=940 |
| 22 | 0.421840 | 198.51.100.7 | 192.168.1.24 | TCP | 54 | 80 → 52310 [ACK] Seq=1 Ack=12621 Win=64240 Len=0 |
| 23 | 0.423940 | 198.51.100.7 | 192.168.1.24 | HTTP | 226 | 80 → 52310 [PSH, ACK] Seq=1 Ack=12621 Win=64240 Len=172 |
| 24 | 0.484140 | 192.168.1.24 | 198.51.100.7 | TCP | 54 | 52310 → 80 [ACK] Seq=12621 Ack=173 Win=64240 Len=0 |
| 25 | 0.484540 | 192.168.1.24 | 198.51.100.7 | TCP | 54 | 52310 → 80 [FIN, ACK] Seq=12621 Ack=173 Win=64240 Len=0 |
| 26 | 0.544740 | 198.51.100.7 | 192.168.1.24 | TCP | 54 | 80 → 52310 [ACK] Seq=173 Ack=12622 Win=64240 Len=0 |
| 27 | 0.545640 | 198.51.100.7 | 192.168.1.24 | TCP | 54 | 80 → 52310 [FIN, ACK] Seq=173 Ack=12622 Win=64240 Len=0 |
| 28 | 0.605840 | 192.168.1.24 | 198.51.100.7 | TCP | 54 | 52310 → 80 [ACK] Seq=12622 Ack=174 Win=64240 Len=0 |
Packet 1 — Packet 1 of 28. The connection begins. SYN = 1, no data, and the sequence number field carries the client’s initial sequence number — the random value §3.5.6 insists on. Wireshark shows it as 0 because it renumbers relative to the start of the connection; the real value is in the bytes below.
Protocol tree — click a field
The actual bytes
0000 aa bb cc 00 00 01 aa bb cc 00 00 11 08 00 45 00 ..............E.0010 00 2c 2b 01 40 00 40 06 23 d0 c0 a8 01 18 c6 33 .,+.@.@.#......30020 64 07 cc 56 00 50 6b 2f 01 00 00 00 00 00 60 02 d..V.Pk/......`.0030 fa f0 78 64 00 00 02 04 05 b4 ..xd......
An HTTP POST of a 12,620-byte file, captured at the sender. Packet 11 never reaches the server. Watch what happens between packets 15 and 21 — that is fast retransmit, and it is the whole reason this capture exists.
The lab’s questions, answered from this trace
What are the port numbers, and the initial sequence numbers?
The client uses ephemeral port 52310 and the server the well-known port
80. The client’s initial sequence number is 1,798,242,560 and the
server’s is 2,753,396,224. They are unrelated, and each side chose its own —
section 3.5.6 explains why they must be hard to guess. Wireshark
renumbers both to start at 0, which is why packet 1 reads Seq=0.
What is the maximum segment size? 1,460 bytes, announced by both sides as an option on their SYN (synchronize) synchronize The TCP flag bit that marks a connection-establishment segment. Set in the first two segments of the three-way handshake (§3.5.6). introduced in ch. 3 . It is 1,500 − 20 − 20: an Ethernet frame’s payload, less the IP (Internet Protocol) Internet Protocol The network-layer protocol that defines the datagram format and addressing every Internet device must use. introduced in ch. 1 header and the TCP header.
What is the estimated round-trip time? Read it off any pair. Packet 4 goes out at 0.0603 and its acknowledgement, packet 5, arrives at 0.1205. The difference is 60.2 ms, and it is the same for every other pair in the trace.
Where is congestion control? In the shape of the sending. One segment (packet 4), then two (packets 6 and 7), then four (packets 10 to 13). That is slow start slow start Simple The opening phase, where the window doubles every round trip — anything but slow. Precise The state a TCP connection begins in. cwnd starts at a small value and grows by one MSS for every segment first acknowledged, which doubles the sending rate every round-trip time. It ends when cwnd reaches ssthresh, when a timeout occurs (cwnd returns to 1 MSS and slow start restarts), or when three duplicate acknowledgements arrive (TCP moves to fast recovery). The name refers to starting from 1 MSS, not to the growth rate. introduced in ch. 3 — open in glossary doubling the congestion window each round trip, exactly as in section 3.7.1. Nothing in any header says so — the congestion window is never transmitted. You are inferring it from the timing, which is what the lab is training you to do.
Where is flow control? In the receive-window field. It sits at 64,240 bytes until packet 16, then falls to 62,780, 61,320 and 59,860 — down exactly 1,460 each time — and returns to 64,240 at packet 20. Section 3.5.5 says the receive window is the free space in the receive buffer, and here you can watch it being consumed.
Where is retransmission? Packet 19, and the four packets before it explain why.
Count duplicates, not acknowledgements
Four packets carry Ack=5841: packets 14, 16, 17 and 18. Only three of them
are duplicates.
Packet 14 is the ordinary cumulative acknowledgement for packet 10, which carried bytes 4381 to 5840. It is the first time 5841 has ever been requested, so it is not a repeat of anything.
Packets 16, 17 and 18 are the duplicate acknowledgements duplicate acknowledgement Simple A second ACK asking again for a byte the sender has already been told about. Precise An acknowledgement that re-acknowledges a segment for which the sender has already had an earlier acknowledgement. The receiver generates one whenever a segment arrives out of order, because TCP has no negative acknowledgement and re-asking is the only way to report a gap. A run of them means the network is still delivering, but something in the middle is missing. introduced in ch. 3 — open in glossary . Each one was produced by a segment arriving past the gap — packets 12, 13 and 15. Each says the same thing: I am still waiting for byte 5841.
Section 3.5.4’s rule counts duplicates, so the trigger is packet 18. A reader who counts acknowledgements instead fires one packet too early, and that is the commonest misreading of fast retransmit.
The recovery, packet by packet
| Packet | Time | What it is |
|---|---|---|
| 11 | 0.1821 | Bytes 5841–7300 are sent. They never arrive. |
| 12, 13 | 0.1833, 0.1845 | The next two segments are sent, and both arrive — past the hole. |
| 14 | 0.2411 | Ack=5841. The cumulative acknowledgement for packet 10. Not a duplicate. |
| 15 | 0.2411 | Packet 14 slid the sender window, so one more segment goes out. The sender still suspects nothing. |
| 16 | 0.2412 | Ack=5841, duplicate 1 — caused by packet 12 arriving. Window drops 1,460. |
| 17 | 0.2412 | Ack=5841, duplicate 2 — caused by packet 13. Window drops another 1,460. |
| 18 | 0.3013 | Ack=5841, duplicate 3 — caused by packet 15, which is why it comes a round trip later. |
| 19 | 0.3014 | Fast retransmit fast retransmit Simple Resending a segment as soon as three duplicate ACKs arrive, without waiting for the timer. Precise On receiving three duplicate acknowledgements for the same data — four acknowledgements of that byte in total — the TCP sender concludes that the segment after the acknowledged one is lost and retransmits it immediately, before its timer expires [RFC 5681]. Since a timeout interval can be far longer than a round-trip time, this removes a large part of the delay caused by a single loss. introduced in ch. 3 — open in glossary . Bytes 5841–7300 again, one tenth of a millisecond after duplicate 3. |
| 20 | 0.3616 | Ack=11681. One acknowledgement jumps 5,840 bytes. |
Two things are worth sitting with.
Packet 19 follows packet 18 immediately. No timer expired. The sender acted on the third duplicate, which is the entire point of the mechanism.
Packet 20 jumps 5,840 bytes. The receiver had bytes 7301 through 11680 the whole time and could not say so, because a cumulative acknowledgement cannot name anything past a gap. The moment the hole was plugged, all four segments became deliverable at once — and the receive window snapped back to 64,240 because those bytes finally left the buffer.
That is section 3.5.4 and section 3.5.5 in the same two numbers.
Every byte here is real
Both checksums in every packet were computed, not invented. You can verify any of them
the way a receiver does. Add up the 16-bit words of the header, including the
checksum field itself, with end-around carry. The answer must be 0xFFFF.
tools/check-capture-ch03.mjs does exactly that for all 28 packets, and
independently re-derives the sequence-number arithmetic, the duplicate count and
the window behaviour from the hex alone.
Wireshark Lab: Exploring UDP
The book’s UDP lab is one short paragraph: capture your favourite UDP application, then investigate the header fields and the checksum calculation. This is the two-datagram exchange from section 2.7.1 — eighteen bytes of text sent and shouted back.
| No. | Time | Source | Destination | Protocol | Length | Info |
|---|---|---|---|---|---|---|
| 1 | 0.000000 | 192.168.1.24 | 198.51.100.7 | UDP | 60 | 51873 → 12000 Len=18 |
| 2 | 0.091200 | 198.51.100.7 | 192.168.1.24 | UDP | 60 | 12000 → 51873 Len=18 |
Packet 1 — One datagram out. No connection was established first — this is the first packet either side has sent, and it already carries application data. Compare the three-way handshake in the chapter 1 capture.
Protocol tree — click a field
The actual bytes
0000 aa bb cc 00 00 01 aa bb cc 00 00 11 08 00 45 00 ..............E.0010 00 2e 4f 21 40 00 40 11 ff a2 c0 a8 01 18 c6 33 ..O!@.@........30020 64 07 ca a1 2e e0 00 1a a7 c3 68 65 6c 6c 6f 20 d.........hello0030 66 72 6f 6d 20 62 61 6e 67 6b 6f 6b from bangkok
A real capture of the book’s example, generated with correct checksums. Click a field to highlight its bytes. The whole conversation is two packets.
The four fields, and nothing else
| Field | Bytes | Value in packet 1 |
|---|---|---|
| Source port | 2 | 51873 |
| Destination port | 2 | 12000 |
| Length | 2 | 26 — the header plus the 18 bytes of data |
| Checksum | 2 | 0xa7c3 |
Eight bytes of header in total, against TCP’s twenty. There is no sequence number, no acknowledgement number, no receive window and no flags, because UDP does none of the things those fields exist for.
Two details that catch people out.
The length includes the header. 26, not 18. So the payload is always
length − 8.
The source port is optional. UDP allows it to be zero when no reply is wanted. Here it is filled in, because the client wants the shouted sentence back.
The checksum, computed
Section 3.3.2 says the checksum covers the UDP header, the data, and a pseudo-header borrowed from the IP header. Here is the whole sum for packet 1, word by word.
The pseudo-header — source address, destination address, a zero byte, the protocol number and the UDP length:
0xc0a8 192.168 — source address, high half
0x0118 .1.24 — source address, low half
0xc633 198.51 — destination address, high half
0x6407 .100.7 — destination address, low half
0x0011 zero byte, then protocol 17 (UDP)
0x001a UDP length, 26The UDP header — with the checksum field taken as zero while computing:
0xcaa1 source port 51873
0x2ee0 destination port 12000
0x001a length 26The data — “hello from bangkok”, two characters per word:
0x6865 "he" 0x6c6c "ll" 0x6f20 "o "
0x6672 "fr" 0x6f6d "om" 0x2062 " b"
0x616e "an" 0x676b "gk" 0x6f6b "ok"Add all of those with end-around carry — every carry out of the top bit is added back at the bottom — and the total is
0x583cInvert every bit:
~0x583c = 0xa7c3which is exactly what the checksum field contains.
Now check it the way the receiver does. Add the same words again, this time including the checksum:
0x583c + 0xa7c3 = 0xffffAll ones. That single test is why the sender inverts the sum instead of sending it directly — the receiver looks for one fixed pattern rather than comparing two numbers. Problem P3 asks you to prove that, and problem P4(c) asks you to break it.
Why UDP borrows fields from the layer below
The pseudo-header is a layering violation, and the book says so. The transport layer is reaching into the network layer’s header to include the IP addresses in its own checksum.
It is there to catch a datagram delivered to the wrong host. Without it, a corrupted destination address in the IP header would still be caught by the IP checksum. But a datagram misrouted for any other reason would arrive at the wrong machine with a perfectly valid UDP checksum, and be accepted.
Programming Assignment: implementing a reliable transport protocol
The book offers this lab in two versions, the alternating-bit version and the Go-Back-N go-back-n Simple A pipelined protocol that, after a loss, resends everything from the missing packet onwards. Precise GBN: the sender may have at most N unacknowledged packets outstanding; acknowledgements are cumulative; there is a single timer, for the oldest unacknowledged packet; and on timeout the sender retransmits every packet that has been sent but not acknowledged. The receiver keeps only one variable, the next expected sequence number, and discards anything out of order. Simple to build, wasteful when the window is large. introduced in ch. 3 — open in glossary version. It supplies a simulated network that can corrupt and lose packets. Both are written out here. They differ in about fifteen lines.
The simulator calls five routines. A_output(message) when the application above
A has data. A_input(packet) when a packet arrives for A. A_timerinterrupt()
when A’s timer expires. And B_input(packet), B_init() on B’s side. You may
call tolayer3(side, packet) to send, tolayer5(side, data) to deliver, and
starttimer(side, increment) / stoptimer(side).
Version 1 — the alternating-bit protocol
This is rdt3.0 from section 3.4.1, turned into code. One packet outstanding, one sequence bit, one timer.
TIMEOUT = 20.0
def checksum(pkt):
"""Sum of the two sequence fields and every payload byte. The simulator
corrupts payloads and sequence numbers, so both must be covered."""
return pkt['seq'] + pkt['ack'] + sum(pkt['payload'].encode())
def corrupt(pkt):
return pkt['checksum'] != checksum(pkt)
# ── sender ────────────────────────────────────────────────────────────────
A = {'seq': 0, 'waiting': False, 'last': None}
def A_output(message):
if A['waiting']:
return # refuse; the layer above must retry
pkt = {'seq': A['seq'], 'ack': 0, 'payload': message, 'checksum': 0}
pkt['checksum'] = checksum(pkt)
A['last'] = pkt
A['waiting'] = True
tolayer3('A', pkt)
starttimer('A', TIMEOUT)
def A_input(pkt):
if corrupt(pkt) or pkt['ack'] != A['seq']:
return # ignore it — P12 explains why
stoptimer('A')
A['seq'] ^= 1 # 0 -> 1 -> 0
A['waiting'] = False
def A_timerinterrupt():
tolayer3('A', A['last']) # the same packet, unchanged
starttimer('A', TIMEOUT)
# ── receiver ──────────────────────────────────────────────────────────────
B = {'expected': 0}
def B_input(pkt):
if corrupt(pkt) or pkt['seq'] != B['expected']:
ack = {'seq': 0, 'ack': 1 - B['expected'], 'payload': '', 'checksum': 0}
else:
tolayer5('B', pkt['payload'])
ack = {'seq': 0, 'ack': B['expected'], 'payload': '', 'checksum': 0}
B['expected'] ^= 1
ack['checksum'] = checksum(ack)
tolayer3('B', ack)
The four lines that matter
if A['waiting']: return — stop-and-wait, enforced. The layer above is told
nothing; the simulator simply retries later. This is the rdt_unable_to_send
of problem P17.
if corrupt(pkt) or pkt['ack'] != A['seq']: return — the sender ignores
anything unexpected. It does not retransmit. Problem
P12 shows what happens if you retransmit here instead: the
protocol stays correct and its cost grows without bound.
tolayer3('A', A['last']) — a timeout resends the stored packet, byte for
byte. Rebuilding it would be a bug: the sequence number must not change.
The else branch in B_input — a duplicate or corrupted packet still gets
an acknowledgement, naming the previous sequence number. Staying silent
would deadlock the sender, which is exactly the failure problem
P6 asks you to construct.
Version 2 — Go-Back-N
Now the sender may have N packets outstanding. Three things change: a sender window instead of a flag, a buffer of unacknowledged packets, and a timeout that resends all of them.
N = 8 # window size
SEQSPACE = 12 # must exceed N — see problem P23
TIMEOUT = 25.0
A = {'base': 0, 'nextseq': 0, 'buffer': {}, 'queue': []}
def A_output(message):
A['queue'].append(message)
_fill_window()
def _fill_window():
"""Send everything the window allows. This is the only place that decides
whether a packet may go out."""
while A['queue'] and (A['nextseq'] - A['base']) % SEQSPACE < N:
pkt = {'seq': A['nextseq'], 'ack': 0,
'payload': A['queue'].pop(0), 'checksum': 0}
pkt['checksum'] = checksum(pkt)
A['buffer'][A['nextseq']] = pkt
tolayer3('A', pkt)
if A['base'] == A['nextseq']:
starttimer('A', TIMEOUT) # one timer, for the oldest packet
A['nextseq'] = (A['nextseq'] + 1) % SEQSPACE
def A_input(pkt):
if corrupt(pkt):
return
# Cumulative: this acknowledges everything up to and including pkt['ack'].
if (pkt['ack'] - A['base']) % SEQSPACE < N:
stoptimer('A')
while A['base'] != (pkt['ack'] + 1) % SEQSPACE:
A['buffer'].pop(A['base'], None)
A['base'] = (A['base'] + 1) % SEQSPACE
if A['base'] != A['nextseq']:
starttimer('A', TIMEOUT) # packets still outstanding
_fill_window()
def A_timerinterrupt():
starttimer('A', TIMEOUT)
seq = A['base']
while seq != A['nextseq']: # go back N — resend the whole window
tolayer3('A', A['buffer'][seq])
seq = (seq + 1) % SEQSPACE
# ── receiver: unchanged in spirit, and still a window of one ──────────────
B = {'expected': 0, 'lastack': SEQSPACE - 1}
def B_input(pkt):
if not corrupt(pkt) and pkt['seq'] == B['expected']:
tolayer5('B', pkt['payload'])
B['lastack'] = B['expected']
B['expected'] = (B['expected'] + 1) % SEQSPACE
ack = {'seq': 0, 'ack': B['lastack'], 'payload': '', 'checksum': 0}
ack['checksum'] = checksum(ack)
tolayer3('B', ack) # always reply, even to a discard
Three traps in the Go-Back-N version
One timer, not N. Go-Back-N has a single timer, and it belongs to the
oldest unacknowledged packet. Start it when base == nextseq before sending;
restart it whenever base moves and packets remain. Giving each packet its own
timer turns this into Selective Repeat, which is a different assignment.
Compare sequence numbers modulo the space, never with <. A['nextseq'] - A['base'] < N
is wrong the moment the numbers wrap. Every comparison here is written
(x - y) % SEQSPACE, and that is not fussiness — it is the bug that makes this
lab take an extra evening.
The receiver still discards out-of-order packets, and still replies. The
if has no else that skips the acknowledgement. Every arriving packet gets
one, and a discarded packet gets a repeat of the last good one. That repeat is
what lets the sender’s window advance when an acknowledgement was lost —
review question R12(b) is exactly this case.
What you should see when it runs
Set the simulator’s loss probability to 0.2 and its corruption probability to 0.2, and watch the difference.
The alternating-bit version delivers everything, slowly. Each loss costs one full timeout, and nothing at all is in flight while it waits.
The Go-Back-N version is much faster and much noisier. Each loss costs one timeout too — but the retransmission carries up to eight packets, most of which the receiver already discarded once. At a loss rate of 0.2 you will see the same payload sent three or four times.
That contrast is the argument for Selective Repeat in section 3.4.4. Problem P37 counts it exactly: nine segments for Go-Back-N against six for Selective Repeat, when one packet out of five is lost.
Check yourself
Check yourself — reading a real trace
0 of 7 answered1.predictFour packets in the TCP capture carry Ack=5841. How many of them are duplicate acknowledgements?
What makes an acknowledgement a duplicate?
2.Packet 11 appears in the capture even though it never reaches the server. Why is it there?
3.predictThe receive window falls from 64,240 to 62,780 to 61,320 to 59,860, then jumps back to 64,240. What is happening?
4.Nothing in any TCP header names the congestion window. How can you see slow start in this capture?
5.Adding all the 16-bit words of the UDP segment — including the checksum field — gives 0xFFFF. What does that tell the receiver?
6.predictIn the Go-Back-N assignment, how many timers should the sender run?
7.Van Jacobson describes finding "ack clocking". What is it?
An interview with Van Jacobson
Voices from the field
Van Jacobson works at Google and was previously a Research Fellow at PARC (Palo Alto Research Center) Palo Alto Research Center Xerox's research centre, where Metcalfe and Boggs invented Ethernet in the mid-1970s. introduced in ch. 6 . Before that he was co-founder and Chief Scientist of Packet Design, and Chief Scientist at Cisco. Earlier still he headed the Network Research Group at Lawrence Berkeley National Laboratory and taught at UC Berkeley and Stanford.
He received the ACM SIGCOMM Award in 2001 for outstanding lifetime contribution to the field. He received the IEEE (Institute of Electrical and Electronics Engineers) Institute of Electrical and Electronics Engineers The body whose 802 committee standardises Ethernet and WiFi. introduced in ch. 1 Kobayashi Award in 2002 for “contributing to the understanding of network congestion and developing congestion control mechanisms that enabled the successful scaling of the Internet”. He was elected to the U.S. National Academy of Engineering in 2004.
Please describe one or two of the most exciting projects you have worked on during your career. What were the biggest challenges?
School teaches us lots of ways to find answers. In every interesting problem I’ve worked on, the challenge has been finding the right question. When Mike Karels and I started looking at TCP congestion, we spent months staring at protocol and packet traces asking “Why is it failing?”. One day in Mike’s office, one of us said “The reason I can’t figure out why it fails is because I don’t understand how it ever worked to begin with.” That turned out to be the right question and it forced us to figure out the “ack clocking” that makes TCP work. After that, the rest was easy.
More generally, where do you see the future of networking and the Internet?
For most people, the Web is the Internet. Networking geeks smile politely since we know the Web is an application running over the Internet but what if they’re right? The Internet is about enabling conversations between pairs of hosts. The Web is about distributed information production and consumption. “Information propagation” is a very general view of communication of which “pairwise conversation” is a tiny subset. We need to move into the larger tent. Networking today deals with broadcast media (radios, PONs, etc.) by pretending it’s a point-to-point wire. That’s massively inefficient. Terabits-per-second of data are being exchanged all over the World via thumb drives or smart phones but we don’t know how to treat that as “networking”. ISPs are busily setting up caches and CDNs to scalably distribute video and audio. Caching is a necessary part of the solution but there’s no part of today’s networking — from Information, Queuing or Traffic Theory down to the Internet protocol specs — that tells us how to engineer and deploy it. I think and hope that over the next few years, networking will evolve to embrace the much larger vision of communication that underlies the Web.
What people inspired you professionally?
When I was in grad school, Richard Feynman visited and gave a colloquium. He talked about a piece of Quantum theory that I’d been struggling with all semester and his explanation was so simple and lucid that what had been incomprehensible gibberish to me became obvious and inevitable. That ability to see and convey the simplicity that underlies our complex world seems to me a rare and wonderful gift.
What are your recommendations for students who want careers in computer science and networking?
It’s a wonderful field — computers and networking have probably had more impact on society than any invention since the book. Networking is fundamentally about connecting stuff, and studying it helps you make intellectual connections: Ant foraging & Bee dances demonstrate protocol design better than RFCs, traffic jams or people leaving a packed stadium are the essence of congestion, and students finding flights back to school in a post-Thanksgiving blizzard are the core of dynamic routing. If you’re interested in lots of stuff and want to have an impact, it’s hard to imagine a better field.
The sentence to take from this page
“The reason I can’t figure out why it fails is because I don’t understand how it ever worked to begin with.”
That is the question that produced congestion control, and it was asked in 1988 about a network that was collapsing. The answer, acknowledgement clocking, is the idea underneath everything in section 3.7. A TCP sender releases a new segment when an acknowledgement arrives. So the acknowledgements returning from the receiver pace the sender at exactly the rate the bottleneck link can carry.
You can see it in the capture at the top of this page. Every burst of data from the client is triggered by an acknowledgement arriving, never by a clock.
What to remember
- The capture is the only place in this chapter where sequence numbers are byte counts you can add up yourself. Do the arithmetic once and §3.5.2 stops being abstract.
- A retransmission looks exactly like the original except for its position in the file. That is the receiver’s whole problem, in hex.
- UDP’s checksum is computed the same way TCP’s is, over a pseudo-header that includes the IP addresses — which is why a transport layer ends up reading network-layer fields.