CS 168 · LECTURE 11 · 2026-10-01 · 传输
IP 可以丢、乱、重,TCP 却向应用提供有序字节流;这层幻觉由序号、累计确认、定时器与重传共同维护。
版本快照:Fall 2026 官方课表与在线教材,核对日期 2026-09-02;官网仍标注 under construction,日期与政策可能变化。
历史证据边界:PointBreaker 仓库只用于复盘 invariant 与 bug,不代表 Fall 2026 当前提交接口。
接收方只返回一个 ACK 数字,发送方怎样判断哪些字节安全、哪些需要重传?
TCP 不保留应用 send() 的消息边界。一次写入可能拆成多个 segment,多次写入也可能合并;接收应用只看到按序字节。因此应用协议必须自行定义长度、分隔符或 framing。
sequence number 标识 segment payload 的第一个字节。SYN 与 FIN 虽不携带应用数据,也各占一个序号空间,使连接建立和关闭能被确认与重传。
若收到 ACK 500,表示 500 之前的所有字节已连续到达。发送方把 snd.una 推到 500,释放相应重传队列项。ACK 不一定对应单个包,而是确认连续前缀。
发送窗口右边界约为 snd.una + advertised_window。snd.nxt - snd.una 是在途字节,真正可发送量是窗口减去在途量;只比较新数据长度与总窗口会在已有未确认数据时超发。
接收方只把连续字节交给应用,乱序 segment 暂存在 receive queue,并重复确认当前 rcv.nxt。缺口补上后,可连续消费多个排队片段并一次推进 ACK。
发送方用超时恢复无反馈的丢包;现代 TCP 还可用重复 ACK 触发快速重传。重传必须使用原序号,且不能把同一逻辑字节重复推进 snd.nxt。
RTT 会变化,所以 RTO 同时估计中心与偏差;先用旧均值更新偏差:
发生重传后,收到 ACK 时无法判断确认的是原包还是重传包,Karn 思路要求不把这次 RTT 当作干净样本。超时还应指数退避,避免拥塞时更猛烈地重发。
初始序号 100,依次收到 payload 范围 [200,300)、[100,150)、[150,200)。每一步写出 receive queue、rcv.nxt 与 ACK。
检查:发送窗口 1000 B,已有 700 B 未确认,当前最多还能新发多少?
| Scenario | 真正稀缺/不确定的对象 | 机制 |
|---|---|---|
| segment 丢失 | 发送方不知道哪些字节已连续抵达 | Reliability:sequence、ACK、timer、retransmission |
| receiver 太慢 | 接收缓存空间 | Flow control:advertised receive window |
| network overloaded | 路径中的队列/链路容量 | Congestion control:根据网络反馈调节发送 |
一个 window 字段不能替代三套机制:接收方有空间不代表网络不拥塞;网络空闲不代表接收应用读得够快;两者都不能告诉发送方具体哪段字节丢了。
检查:接收端应用暂停读取、但网络空闲,首先限制发送方的应是什么?
初始发送方 SND.UNA=100、SND.NXT=100、SND.WND=400;接收方 RCV.NXT=100、receive window 400、乱序队列为空。
| Step / event | Sender after | Receiver after | wire output | 为何这样更新 |
|---|---|---|---|---|
| 0 · initial | UNA=100, NXT=100, retx=[] | NXT=100, OOO=[] | — | 没有在途字节 |
| 1 · send [100,200), lost | UNA=100, NXT=200, retx=[[100,200)];启动 oldest-unacked timer | 不变 | segment 消失 | 发送推进 NXT,但未确认不能推进 UNA |
| 2 · send [200,300), arrives | UNA=100, NXT=300, retx 两项 | NXT=100, OOO=[[200,300)] | ACK 100 | [100,200) 是洞,不能越洞交付 |
| 3 · ACK 100 arrives | UNA 仍 100;队列不弹出 | 不变 | — | 累计 ACK 没有确认新连续字节 |
| 4 · timeout oldest | 重发 [100,200),NXT 仍 300;RTO backoff | 不变 | retransmit seq=100 | 重传同一逻辑字节,不能再次消耗序号 |
| 5 · retransmission arrives | 等待 ACK | 先交付 [100,200),再从 OOO 连续取 [200,300);NXT=300, OOO=[] | ACK 300 | 缺口闭合后连续前缀一次扩展两段 |
| 6 · ACK 300 arrives | UNA=300, NXT=300, retx=[];停止 timer | NXT=300 | — | 所有在途字节成为已确认前缀 |
发送空间始终满足 \(\mathrm{SND.UNA} \leq \mathrm{SND.NXT} \leq \mathrm{SND.UNA}+\mathrm{SND.WND}\)。接收端只向应用交付小于 RCV.NXT 的连续前缀。
检查:Step 2 收到 [200,300) 后,RCV.NXT 应是多少?
检查:Step 4 重传后,SND.NXT 为什么不变成 400?
对未重传样本 \(R\),先用旧均值更新偏差,再更新均值:\[\mathrm{RTTVAR}\leftarrow(1-\beta)\mathrm{RTTVAR}+\beta\lvert \mathrm{SRTT}_{\mathrm{old}}-R\rvert\] \[\mathrm{SRTT}\leftarrow(1-\alpha)\mathrm{SRTT}_{\mathrm{old}}+\alpha R\] \[\mathrm{RTO}=\mathrm{SRTT}+\max(G,4\,\mathrm{RTTVAR})\]
SRTT 跟踪中心,RTTVAR 为抖动留余量,G 是时钟粒度。若包被重传,随后 ACK 可能对应原发送或重传,样本归属不可辨识;Karn 的原则是跳过该 RTT 样本,并在 timeout 后退避 RTO。
应用会先读到 [200,300),以后再读 [100,200),TCP 对“有序字节流”的承诺被破坏。若仍发送 ACK 300,发送方还会删除其实未到的 [100,200);可靠性状态与应用可见结果同时损坏。OOO queue 的存在不是性能优化,而是把已收到集合与可交付连续前缀分开。
RCV.NXT 才交付;遇洞停止。这些映射来自你的历史仓库,用来复盘 invariant 与 bug;不是 Fall 2026 Project 3 官方答案。当前官方 P3 仍未发布。
检查:ACK 300 到达时,发送方可删除哪些重传项?
检查:网络严重拥塞但 receiver window 很大,哪项仍必须独立限制发送?
检查:为什么重传后的 ACK 不宜更新 SRTT?
如果答案没有说明“连续前缀”“重传不推进 NXT”“receiver state 与 network state 不同”,继续重画 timeline。
正文是 CourseStack 的中文解释与重新绘制的教学例子;官方页面负责课程原始定义,历史仓库只提供你的实现证据。