COMP5416 Week 05 传输层讲课总结

COMP5416 Week 05 讲课总结:Transport Layer

课程:COMP5416/COMP4416 — Advanced Network Technologies,Semester 2 2026 讲师:Professor Vincent Gramoli 讲义W5-Transport.pdf(60 页) 教材:Kurose & Ross 9th ed. —— 第 3 章,3.1 / 3.2 / 3.3 / 3.4 节

⚠️ Midterm quiz 在 Week 6,20 道选择题,占 20%。老师已说明:期中不考 Week 6 的内容,范围就是 Week 1–5 —— 本讲是考纲的最后一周。

本讲是考纲里计算题最密集的一周 —— 利用率公式、校验和手算、GBN/SR 行为推演都在这里。

本讲学习目标(讲义 p3)

理解传输层服务背后的原理

  • 多路复用、分解(multiplexing, demultiplexing)
  • 可靠数据传输(reliable data transfer)
  • 流量控制(flow control)
  • 拥塞控制(congestion control)

了解互联网的传输层协议

  • UDP:无连接传输
  • TCP:面向连接的可靠传输
  • TCP 拥塞控制

注意:本周只讲到 rdt 原理与流水线协议。流量控制、拥塞控制、TCP 协议本身要到 Week 6。


第一部分:传输层服务

一、传输层做什么

传输层在运行于不同主机上的应用进程之间提供逻辑通信。 传输协议运行在端系统里(不在网络核心设备上)。

发送侧与接收侧的动作

动作
发送侧 把应用消息拆成段(segments),交给网络层
接收侧 把段重组成消息,交给应用层

术语要分清(考试会用词区分层次):

数据单元的名字
应用层 message(消息)
传输层 segment(段)
网络层 datagram(数据报)
链路层 frame(帧)

应用可用的传输协议不止一个 —— 互联网上是 TCP 和 UDP

二、传输层 vs 网络层(必考区分)

网络层 传输层
通信对象 主机到主机(host-to-host) 进程到进程(process-to-process)
性质 尽力而为、不可靠 依赖并增强网络层的服务

一句话记住网络层把数据送到「那台机器」,传输层把数据送到「那个进程」。

为什么说「增强」:网络层的 IP 只能保证「尽量把包送到那台机器」,丢包、乱序、重复都可能发生。 TCP 在这个基础上加了序号、ACK、重传、定时器,把不可靠的 IP 变成可靠的字节流 —— 这就是本讲后半段 rdt 要讲的东西。

三、互联网的两个传输层协议

服务 TCP UDP
可靠、按序交付
拥塞控制
流量控制
连接建立
时延保证
带宽保证

UDP 的定位(讲义原文):对「尽力而为」IP 的无修饰扩展(no-frills extension of "best-effort" IP)

两者都不提供的服务是高频陷阱选项时延保证、带宽保证。 无论选 TCP 还是 UDP,都拿不到「延迟不超过 X 毫秒」或「带宽至少 Y Mbps」的承诺 —— 那需要网络层的 QoS 支持。


第二部分:多路复用与分解

四、基本概念

定义
发送方的多路复用(multiplexing) 处理来自多个套接字的数据,添加传输层首部(供之后分解用)
接收方的分解(demultiplexing) 用首部信息把收到的段交付给正确的套接字

分解的工作流程

  1. 主机收到 IP 数据报,每个数据报有源 IP 地址、目的 IP 地址
  2. 每个数据报携带一个传输层段
  3. 每个段有源端口号、目的端口号
  4. 主机用 IP 地址和端口号把段导向正确的套接字

段格式中与分解相关的部分

┌────────────────┬────────────────┐
│ 源端口号 (16) │ 目的端口号 (16) │ ← 32
├────────────────┴────────────────┤
│ 其他首部字段 │
├─────────────────────────────────┤
│ 应用数据(payload) │
└─────────────────────────────────┘

五、无连接分解(UDP)

UDP 套接字只由「二元组」标识:目的 IP + 目的端口号。

接收方的动作

  1. 检查收到的 UDP 段中的目的端口号
  2. 把段导向拥有该端口号的套接字

发送方的动作:创建要发进 UDP 套接字的数据报时,必须指定目的 IP 地址和目的端口号

clientSocket.sendto(message, (destIP, destPort))

讲义 p12 最关键的一句「目的 IP、目的端口相同,但源 IP 和/或源端口不同的分组,会被导向目的地的同一个套接字。」

换句话说:UDP 不区分发送方。 一个 UDP 服务器套接字会收到所有发往该端口的数据报, 想知道是谁发来的,只能靠 recvfrom() 返回的地址自己判断。

讲义 p13 的例子(要能读懂)

主机 套接字端口
服务器 DatagramSocket(6428)
客户 1 DatagramSocket(9157)
客户 2 DatagramSocket(5775)

段的流向

方向 源端口 目的端口
客户 1 → 服务器 9157 6428
客户 2 → 服务器 5775 6428
服务器 → 客户 1 6428 9157
服务器 → 客户 2 6428 5775

注意:两个客户发来的段目的端口都是 6428,所以都进同一个服务器套接字。 服务器回复时,把收到的源端口当作目的端口填回去 —— 这就是「源端口号提供了返回地址」的含义。

六、面向连接分解(TCP)

TCP 套接字由「四元组(4-tuple)」标识源 IP + 源端口 + 目的 IP + 目的端口

接收方用全部四个值把段导向正确的套接字。

三个重要推论

推论 说明
服务器可同时支持很多 TCP 套接字 每个由自己的四元组标识
Web 服务器为每个连接的客户建立不同的套接字
非持久 HTTP 为每个请求都建立不同的套接字 这也是非持久 HTTP 开销大的原因之一

讲义 p15 的例子(必须能读懂)

三个段全都发往 IP=B, 目的端口=80,却被分解到不同的套接字

源 IP, 源端口 目的 IP, 目的端口 进入哪个套接字
A, 9157 B, 80 套接字 1
C, 5775 B, 80 套接字 2
C, 9157 B, 80 套接字 3

②和③的对比是本例的精华两个段的源 IP 相同(都是 C)、目的完全相同,只有源端口不同(5775 vs 9157),就被分到了不同的套接字。 这正说明 TCP 用的是四元组而非二元组。

💡 讲义 p16 补充:若是多线程服务器,这些套接字会分给不同的线程处理。

七、UDP 二元组 vs TCP 四元组(本讲最经典的 MCQ)

UDP TCP
套接字标识 二元组:目的 IP + 目的端口 四元组:源 IP + 源端口 + 目的 IP + 目的端口
不同源发来的段 进同一个套接字 进不同的套接字
服务器区分客户靠什么 应用自己从 recvfrom() 拿地址 传输层自动按四元组区分

第三部分:UDP

八、UDP 的特性 [RFC 768]

特性 说明
定位 「无修饰(no frills)」的互联网传输协议
服务 「尽力而为」 —— 段可能丢失乱序交付给应用
无连接 发送方与接收方之间无握手每个 UDP 段独立处理

九、为什么要有 UDP(必考四点)

讲义 p19 直接抛出了这个问题:"why is there a UDP?"

理由 说明
无连接建立 连接建立会增加时延(TCP 要三次握手)
简单 发送方、接收方都不维护连接状态
首部小 只有 8 字节(TCP 首部 20 字节起)
无拥塞控制 UDP 想多快发多快(can blast away as fast as desired)

第四点是双刃剑:对实时音视频是优点(不会因为网络拥塞而被迫降速导致卡顿), 但也意味着 UDP 流量不「谦让」,可能挤垮 TCP 流量 —— 这是网络公平性的经典议题。

UDP 的典型用途

  • 流媒体应用(容忍丢失、对速率敏感)
  • DNS

想在 UDP 上要可靠传输怎么办在应用层加可靠性 —— 应用特定的差错恢复。 (现代例子:QUIC 就是在 UDP 之上重新实现了可靠传输和拥塞控制。)

十、UDP 段格式

┌────────────────┬────────────────┐
│ 源端口号 (16) │ 目的端口号 (16) │
├────────────────┼────────────────┤
│ length (16) │ checksum (16) │
├────────────────┴────────────────┤
│ │
│ 应用数据(payload) │
│ │
└─────────────────────────────────┘
字段 大小 说明
源端口号 16 位 范围 0–65535
目的端口号 16 位
length 16 位 UDP 段的字节长度,含首部
checksum 16 位 差错检测

首部大小 = 4 × 2 = 8 字节,这是必背数字。 length 的最小值是 8(没有数据时,只有首部)。


第四部分:Internet 校验和(会考手算)

十一、算法

目标:检测传输中的「差错」(如比特翻转)。

步骤
发送方 ① 把段内容(含首部字段)视为一串 16 位整数
求和(反码和 one's complement sum)
校验和 = 和的反码(取反)
④ 把校验和放进 UDP 校验和字段
接收方 ① 计算收到段的校验和
比较是否等于校验和字段的值
  不等 → 检测到差错;相等 → 未检测到差错

十二、关键细节:回卷进位(wraparound)

讲义原话「相加时,来自最高有效位的进位需要加回到结果上。」

这一步最容易漏,也是手算题的主要失分点。

讲义 p21 的完整手算(逐位验算过)

第一步:两个 16 位整数相加

  1110011001100110      (0xE666)
+ 1101010101010101 (0xD555)
─────────────────────
11011101110111011 17 位!最高位的 1 是进位(carryout)

第二步:回卷 —— 把进位加回低 16 位

  1011101110111011      ← 低 16 
+ 1 ← 进位
─────────────────────
1011101110111100 ← 回卷和(sum)

第三步:取反得校验和

sum      = 1011101110111100
取反 →
checksum = 0100010001000011

自检技巧回卷和 + 校验和应当全为 1。 本例:1011101110111100 + 0100010001000011 = 1111111111111111

十三、接收方验证(讲义 p22)

讲义原话"Use checksum as addend: Checksum should be 0" —— 把校验和当作一个加数一起求和,最后取反应得全 0。

⚠️ 注意 p22 换了字长p21 用的是两个 16 位字,p22 用的是四个 8 位字。 讲义没有说明这个切换,容易看串。下面按 p22 实际的 8 位口径推。

左半边:发送方算校验和

  10010010        ← 146
00110100 ← 52
+ 01010110 ← 86
01111000 ← 120
──────────────
110010100 ← 和 = 404,共 9 位,最高位是进位

回卷:把第 9 位的进位加回低 8 位

  10010100        ← 低 8 位(148)
+ 1 ← 进位
──────────────
10010101 ← SUM(149)

取反得校验和

SUM      = 10010101
取反 →
CHECKSUM = 01101010106

右半边:接收方验证

把校验和也当成一个加数加进去

  10010010
00110100
01010110
01111000
+ 01101010 ← 校验和
──────────────
111111110 ← 和 = 5109

回卷

11111110  +  1  =  11111111      ← 全 1

取反

取反 → 00000000      ← 全 0 ⇒ 无差错

MCQ 常问「接收方验证时结果应该是什么」 —— 答案是 全 0(把校验和一起加进去,回卷后取反)。 等价说法:所有字(含校验和)的反码和应为全 1。

💡 想多练Kurose 官方交互题 Internet checksum 可以无限刷随机实例(用的是 16 位口径),每做一次都会重新出题

校验和的局限(值得知道)

校验和只能「检测」差错,不能「纠正」差错。 而且它检测不出所有差错 —— 例如两个比特同时翻转且相互抵消时,校验和不变。 真正的可靠性靠的是「校验和 + 序号 + ACK + 重传」的组合,这正是下一节 rdt 要讲的。


第五部分:可靠数据传输原理(rdt)

十四、为什么重要

在应用层、传输层、链路层都很重要 —— 网络十大重要话题之一。 底层信道的特性决定了 rdt 协议的复杂度。

讲义 p24–26 用三张递进的图强调:可靠数据传输协议要在不可靠的网络层之上建立可靠的抽象。

十五、四个接口函数(要认得)

函数 谁调用 作用
rdt_send() 上层调用(如应用) 传入要交付给接收方上层的数据
udt_send() 由 rdt 调用 把分组通过不可靠信道传给接收方
rdt_rcv() 信道调用 分组到达接收侧时被调用
deliver_data() 由 rdt 调用 把数据交付给上层

命名规律rdt_ = reliable data transfer(可靠的);udt_ = unreliable data transfer(不可靠的)。 udt_send() 是唯一真正把数据丢进不可靠信道的函数。

方法论用有限状态机(FSM)描述发送方与接收方只考虑单向数据传输,但控制信息双向流动。

十六、rdt 的演进(必背这张表)

版本 信道假设 新增机制
rdt1.0 完全可靠:无比特差错、无丢包
rdt2.0 可能翻转比特 ① 差错检测(校验和)② 接收方反馈:ACK / NAK
rdt2.1 同上 序号(0/1) —— 处理 ACK/NAK 自身被损坏
rdt2.2 同上 无 NAK 协议 —— 只用带序号的 ACK
rdt3.0 还会丢包(数据和 ACK 都可能丢) 倒计时定时器 + 超时重传

记忆线索每一版只解决前一版暴露的一个新问题。 1.0 什么都不做 → 2.0 处理比特错 → 2.1 处理「反馈本身也会错」→ 2.2 简化掉 NAK → 3.0 处理丢包。

十七、rdt1.0:完全可靠的信道

假设无比特差错、无丢包。

发送方 FSM(只有一个状态):

[Wait for call from above]
rdt_send(data)
packet = make_pkt(data)
udt_send(packet)

接收方 FSM(只有一个状态):

[Wait for call from below]
rdt_rcv(packet)
extract(packet, data)
deliver_data(data)

这一版没有任何反馈 —— 发送方发完就不管了,因为假设信道完美。

十八、rdt2.0:有比特差错的信道

新假设底层信道可能翻转分组中的比特。

解决思路

机制 作用
校验和 检测比特差错
ACK(肯定确认) 接收方显式告诉发送方「分组收到了,没问题」
NAK(否定确认) 接收方显式告诉发送方「分组有错」
重传 发送方收到 NAK 后重传该分组

讲义的类比很好「人类在对话中是怎么从『错误』中恢复的?」 —— 听不清就说「你再说一遍」,这就是 NAK。

rdt2.0 新增的两个机制(相对 rdt1.0):

  1. 差错检测
  2. 接收方反馈:控制消息(ACK/NAK)从接收方到发送方

发送方 FSM(两个状态):

[Wait for call from above]
rdt_send(data) → sndpkt = make_pkt(data, checksum); udt_send(sndpkt)

[Wait for ACK or NAK]
收到 NAK → udt_send(sndpkt) (重传,留在本状态)
收到 ACK → 回到 [Wait for call from above]

停等(stop-and-wait)的定义发送方发一个分组,然后等待接收方的响应。 rdt2.0 及之后的所有版本都是停等协议,直到引入流水线。

十九、rdt2.0 的致命缺陷与 rdt2.1

缺陷:如果 ACK/NAK 本身被损坏了怎么办?

问题 说明
发送方不知道接收方发生了什么 收到的反馈是乱码,无法判断是 ACK 还是 NAK
不能简单重传 可能造成重复 —— 万一原本是 ACK,重传就多发了一份

rdt2.1 的解决办法

措施 说明
ACK/NAK 损坏时发送方重传当前分组 宁可重复也不能漏
发送方给每个分组加序号 两个序号(0, 1)就够了
接收方丢弃重复分组 不向上交付,但仍然要回 ACK

为什么两个序号就够(经典 MCQ)

因为是停等协议,任何时刻只有一个分组「在飞」。 接收方只需区分「这个分组是我在等的那个,还是上一个的重复」 —— 一个比特就能表达。

rdt2.1 的状态数

说明
发送方 状态数翻倍(4 个);状态必须「记住」当前该用序号 0 还是 1
接收方 必须检查收到的分组是不是重复状态指示期望的是 0 还是 1

发送方的四个状态

[Wait for call 0 from above] → [Wait for ACK/NAK 0]
↓ (收到好的 ACK)
[Wait for call 1 from above] → [Wait for ACK/NAK 1]
↓ (收到好的 ACK)
回到最上面

接收方对损坏分组的处理(讲义 p37):发 NAK对重复分组的处理重发 ACK(不是 NAK!)—— 因为分组本身是好的,只是重复了。

二十、rdt2.2:无 NAK 协议

与 rdt2.1 功能完全相同,但只用 ACK。

改动 说明
接收方不发 NAK 改为对「最后一个正确收到的分组」发 ACK
ACK 必须带序号 接收方必须在 ACK 中显式包含被确认分组的序号
发送方的判断 收到「非预期序号的 ACK」时,动作与收到 NAK 相同:重传当前分组

举例:发送方正在等 ACK0,却收到了 ACK1 —— 说明接收方还停在上一个分组,等同于 NAK,于是重传 pkt0。

💡 这就是「重复 ACK(duplicate ACK)」概念的起源。 TCP 的快速重传(fast retransmit)正是基于「收到 3 个重复 ACK 就立刻重传」 —— Week 6 会讲。

二十一、rdt3.0:处理丢包

新假设:底层信道还会丢分组(数据、ACK 都会丢)。 校验和、序号、ACK、重传都有帮助……但还不够。

为什么不够:如果分组彻底丢了,接收方根本不知道该发什么反馈,发送方就会永远等下去。

方法发送方等待「合理」的时间;若超时未收到 ACK 则重传。

要点 说明
需要倒计时定时器 countdown timer —— 这是 rdt3.0 唯一的新机制
分组只是延迟而非丢失时 重传会产生重复,但序号机制已能处理
接收方必须指明 ACK 的序号 沿用 rdt2.2 的做法

发送方 FSM 的关键动作

rdt_send(data) → make_pkt(seq, data, checksum); udt_send; start_timer
timeout → udt_send(sndpkt); start_timer (重传并重启定时器)
收到正确的 ACK → stop_timer

讲义 p43–44 的四个场景(要能画出时序图)

场景 发生了什么 结果
(a) 无丢失 正常一来一回 无重传
(b) 分组丢失 pkt1 在途中丢失 超时 → 重传 pkt1
(c) ACK 丢失 pkt1 到了,但 ack1 丢失 超时 → 重传 pkt1 → 接收方检测到重复,重发 ack1
(d) 过早超时 / ACK 延迟 ack1 只是慢了,不是丢了 重传后收到两个 ack1,第二个「do nothing」

场景 (c) 和 (d) 的区别值得琢磨

  • (c) 中接收方收到了重复分组 —— 靠序号识别,丢弃但仍回 ACK
  • (d) 中发送方收到了重复 ACK —— 直接忽略

两种重复分别由「接收方的序号检查」和「发送方的状态机」处理,这是 rdt 设计的对称之美。


第六部分:性能与流水线

二十二、停等协议的利用率(必考计算)

公式

符号 含义
分组长度(比特)
链路速率(bps)
往返时间
传输时延

物理含义发送方「忙于发送」的时间占整个周期的比例。

时间轴拆解(讲义 p46)

t = 0              第一个比特送出
t = L/R 最后一个比特送出 ← 发送方只在这段时间「忙」
... 分组在链路上传播
... 接收方收完,发 ACK
t = RTT + L/R ACK 到达,可以发下一个 ← 一个完整周期

讲义 p45 的算例(逐步验算过)

参数1 Gbps 链路,15 ms 传播时延(RTT = 30 ms),8000 比特分组

讲义的结论(要会说)在 1 Gbps 的链路上,每 30 ms 才发 1 KB,只跑出 33 kB/s —— 「网络协议限制了物理资源的使用!」

不同参数下的利用率对照(自己算的,帮助理解规律)

场景 (停等)
1 Gbps, 8000 bit, RTT 30 ms 0.008 ms 0.027%
100 Mbps, 8000 bit, RTT 10 ms 0.080 ms 0.79%
10 Mbps, 1000 bit, RTT 20 ms 0.100 ms 0.50%
1 Mbps, 1000 bit, RTT 20 ms 1.000 ms 4.76%

规律: 相对 越小,利用率越低。 链路越快、RTT 越大,停等协议就越浪费 —— 这正是「高带宽-高时延(long fat pipe)」网络的经典问题。

延伸:要多大的窗口才能占满链路

代入讲义的例子 个分组

也就是说,那条 1 Gbps 链路要有近 3751 个分组同时「在飞」才能被占满。 这个数就是所谓的带宽时延积(bandwidth-delay product)除以分组大小。

二十三、流水线(Pipelining)

定义:发送方允许多个「在飞的」、尚未确认的分组。

需要什么

要求 原因
序号范围必须扩大 停等只要 2 个序号,流水线要能区分窗口内的所有分组
发送方和/或接收方要缓存 发送方要留着未确认的分组以备重传;接收方可能要缓存乱序分组

两种通用的流水线协议Go-Back-NSelective Repeat

流水线的利用率公式

讲义 p48 的 3 分组例子

恰好是停等的 3 倍 —— 「流水线 N 个分组,利用率提升 N 倍」。

⚠️ 讲义 p48 有两处印刷问题,自己算时会撞上

  1. 讲义写 .0024,应为 .024,小数点错位)
  2. 讲义得数写 0.00081,精确值是 0.0008 —— 差异来自讲义拿「已四舍五入的 0.00027」乘 3

考试按 直接算即可,结论「提升 N 倍」不变。


第七部分:Go-Back-N vs Selective Repeat

二十四、六维对比表(最高频 MCQ)

维度 Go-Back-N(GBN) Selective Repeat(SR)
发送方窗口 最多 N 个未确认分组 最多 N 个未确认分组
ACK 类型 累积 ACK(cumulative) 对每个分组单独 ACK
定时器 只为「最老的未确认分组」设 1 个 每个未确认分组各 1 个
超时重传 重传该分组及窗口内所有更高序号的分组 只重传那一个分组
接收方缓存 不缓存!乱序分组直接丢弃 缓存乱序分组
接收方对乱序分组 重发「最高按序序号」的 ACK 发该分组自己的 ACK

两个最容易被考的差异

  1. GBN 接收方「不缓存」 —— 讲义 p53 明写 "discard (don't buffer): no receiver buffering!"
  2. GBN 只有一个定时器(给最老的未确认分组),SR 每个分组一个

设计哲学的对比

GBN SR
接收方复杂度 极简(只记 expectedseqnum 复杂(要维护接收窗口和缓存)
带宽效率 (丢一个要重传一批) (只重传丢的那个)
适用场景 丢包率低、带宽充裕 丢包率高、带宽宝贵

一句话概括GBN 把复杂度留给发送方(重传更多),SR 把复杂度留给接收方(缓存更多)。

二十五、Go-Back-N 详解

发送方

  • 窗口 = 最多 N 个连续的未确认分组
  • ACK(n) 确认「直到并包含序号 n」的所有分组 —— 累积 ACK
  • 可能收到重复 ACK
  • 只为「最老的在飞分组」设定时器
  • timeout(n):重传分组 n 及窗口内所有更高序号的分组

发送方的三个变量

变量 含义
base 窗口最左端(最老的未确认分组序号)
nextseqnum 下一个要发送的序号
N 窗口大小

发送逻辑(讲义 p52 的 FSM):

rdt_send(data):
if (nextseqnum < base + N): ← 窗口没满
发送 pkt[nextseqnum]
if (base == nextseqnum): start_timer ← 是最老的就启动定时器
nextseqnum++
else:
refuse_data(data) ← 窗口满了,拒绝上层数据

收到 ACK(n):
base = n + 1 ← 窗口右移
if (base == nextseqnum): stop_timer
else: start_timer ← 还有在飞的,重启定时器

timeout:
start_timer
重发 pkt[base] ... pkt[nextseqnum - 1] ← 全部重发

接收方

ACK-only:总是对「已正确按序收到的最高序号分组」发 ACK。

特性 说明
可能产生重复 ACK 收到乱序分组时会重复确认同一个序号
只需记住 expectedseqnum 接收方状态极简
乱序分组 丢弃(不缓存),然后重发最高按序序号的 ACK

讲义 p54 的完整时序推演(N = 4,pkt2 丢失)

时刻 发送方 接收方
1 发 pkt0, pkt1, pkt2, pkt3(窗口满)
2 收 pkt0 → 发 ack0
3 收 pkt1 → 发 ack1
4 pkt2 丢失
5 收 ack0 → 发 pkt4
6 收 ack1 → 发 pkt5
7 收 pkt3 → 丢弃!重发 ack1
8 收 pkt4 → 丢弃!重发 ack1
9 收 pkt5 → 丢弃!重发 ack1
10 pkt2 超时
11 重发 pkt2, pkt3, pkt4, pkt5(4 个!)
12 依次收下并交付,发 ack2, ack3, ack4, ack5

发送方对重复的 ack1 是「忽略」 —— GBN 没有快速重传机制,只能等超时。 注意 pkt3/4/5 白白传了一遍又被丢弃 —— 这就是 GBN 浪费带宽的地方。

二十六、Selective Repeat 详解

核心特性

  • 接收方对每个正确收到的分组单独确认
  • 按需缓存分组,以便最终按序交付给上层
  • 发送方只重传未收到 ACK 的分组
  • 发送方为每个未确认分组设定时器
  • 有发送方窗口和接收方窗口

发送方的三种事件(讲义 p57)

事件 动作
上层来数据 若窗口内有可用序号,就发送
timeout(n) 只重发 pkt n,重启该分组的定时器
收到 ACK(n),且 n 在 [sendbase, sendbase+N-1] 标记 pkt n 已收到若 n 是最小的未确认分组,窗口前移到下一个未确认序号

接收方的三种情况(考点)

收到的分组 n 动作
[rcvbase, rcvbase+N-1] 发 ACK(n)乱序 → 缓存按序 → 交付(连同已缓存的按序分组),窗口前移
[rcvbase-N, rcvbase-1] 仍然要发 ACK(n)!
其他 忽略

第二行是最容易忽略的一条分组明明已经交付过了,为什么还要 ACK? 因为这说明发送方没收到之前的 ACK(ACK 丢了),如果不再 ACK 一次,发送方的窗口就永远前移不了,会死锁。

讲义 p59 的完整时序推演(同样 N = 4,pkt2 丢失)

时刻 发送方 接收方 与 GBN 的差异
1 发 pkt0–pkt3
2–3 收 pkt0, pkt1 → ack0, ack1
4 pkt2 丢失
5–6 收 ack0/ack1 → 发 pkt4, pkt5
7 收 pkt3 → 缓存,发 ack3 GBN 会丢弃并重发 ack1
8 收 pkt4 → 缓存,发 ack4 GBN 会丢弃
9 收 pkt5 → 缓存,发 ack5 GBN 会丢弃
10 记录 ack3/ack4/ack5 已到 GBN 会忽略这些
11 pkt2 超时 → 只重发 pkt2(1 个) GBN 重发 4 个
12 收 pkt2 → 一次性交付 pkt2, pkt3, pkt4, pkt5,发 ack2 GBN 要逐个重收

这一对例子(p54 vs p59)几乎必考 —— 记住「同样丢 pkt2,GBN 重传 4 个,SR 只重传 1 个」。

重传量的一般规律

窗口 N 丢失位置 GBN 重传数 SR 重传数
4 第 1 个 3 1
6 第 1 个 5 1
8 第 3 个 5 1

GBN 重传数 = 从丢失的那个起,窗口内已发出的分组个数。

二十七、序号空间的最小要求(讲义未展开但常考)

协议 序号空间下限 理由
停等(rdt2.1/3.0) 2 只需区分「这个」和「下一个」
GBN N + 1 接收窗口大小为 1
SR 2N 收发窗口可能完全不重叠

SR 为什么要 2N:如果序号空间只有 N,接收方无法区分「新分组」和「上一轮的重传」, 会把旧数据当新数据交付给上层。这是 SR 的经典陷阱题。


第八部分:配套 Tutorial —— DNS

⚠️ tutorial 比 lecture 慢一周 —— Week 5 模块里这份 tutorial 练的是 Week 04 的 DNS,不是本讲的传输层。

官方答案(Tutor's version)已拿到并逐条核对完毕完整解答独立成篇Week 05 Tutorial:DNS 与 HTTP 时延

二十八、要点速览

Exercise 内容 关键结论
1 13 道 DNS 概念题 协议 Both端口 53先问 Local DNS记录存在 AuthoritativeTLD 转介返回 NS + A 两条
2 HTTP 与 DNS 时延 148 / 508 / 268 / 208 ms持久并行最快

Exercise 2 的四个答案 ms):

情形 计算 结果
单对象 148 ms
非持久·串行,n=3 508 ms
非持久·并行(上限 5) 268 ms
持久·并行 208 ms

二十九、通用公式(背下来,考试直接套)

情形 公式
非持久·串行(n 个引用对象)
非持久·并行(上限 k 条)
持久 + 并行(上限 k 条)

记忆逻辑

  • 基础对象永远要 2 个 RTT(建连 + 请求)
  • 非持久串行每个引用对象再各要 2 个 RTT
  • 非持久并行每一轮 2 个 RTT,轮数 =
  • 持久并行每一轮只要 1 个 RTT(不用重建连接),轮数仍是

⚠️ 持久那条别写成恒定的 —— 本题 只有一轮才凑巧等于 3。 时要分轮,例如 。 只有「持久 + 流水线、不限并行数」才是所有对象共 1 个 RTT。

⚠️ 官方答案 PDF 另有两处与题面不一致(Q3 的类型数、Q9 的 IP), 详见 Tutorial 笔记


第九部分:MCQ 速查表

分层与分解

答案
网络层 vs 传输层 主机到主机 vs 进程到进程
UDP 套接字标识 二元组:目的 IP + 目的端口
TCP 套接字标识 四元组:源 IP + 源端口 + 目的 IP + 目的端口
传输层数据单元 segment(段)
UDP 首部大小 8 字节(4 个字段各 2 字节)
TCP/UDP 都不提供 时延保证、带宽保证

UDP

答案
为什么要 UDP 无连接建立时延、无连接状态、首部小、无拥塞控制
典型用途 流媒体、DNS
想要可靠怎么办 在应用层加
length 字段 含首部的字节数,最小 8
校验和验证结果 把校验和一起加进去 → 全 1 → 取反全 0
校验和能力 只能检测差错,不能纠正;也检测不出所有差错

rdt 演进

版本 信道假设 新机制
rdt1.0 完美
rdt2.0 有比特错 校验和 + ACK/NAK
rdt2.1 有比特错 序号(0/1)
rdt2.2 有比特错 无 NAK,ACK 带序号
rdt3.0 还会丢包 定时器 + 超时重传

性能

公式
停等利用率
流水线利用率
占满链路所需窗口
讲义算例 1 Gbps、RTT 30 ms、8000 bit → U = 0.00027,吞吐 33 kB/s

GBN vs SR

GBN SR
ACK 累积 单独
定时器 1 个 每包 1 个
重传 N 个 1 个
接收方缓存 不缓存 缓存
接收窗口 1 N
序号空间下限 N + 1 2N

最容易错的 6 个点

  1. UDP 是二元组,TCP 是四元组 —— 别记反
  2. 校验和要回卷进位,漏掉就全错
  3. 接收方验证的结果是全 0(不是全 1 —— 全 1 是取反之前)
  4. GBN 接收方不缓存 —— 这是它要重传 N 个的根本原因
  5. SR 对「已交付过的旧分组」仍要 ACK,否则发送方窗口卡死
  6. 停等利用率公式的分母是 ,不是只有

第十部分:本讲在考纲中的位置

Week 主题 笔记
1 Introduction Week 01
2 Performance Week 02
3 Applications Week 03
4 DNS and P2P Week 04
5 Transport 本文
6 TCP ⚠️ Canvas 未发布

本讲是 Week 6 TCP 的直接铺垫。 把本讲的机制拼起来,基本就是 TCP 的可靠传输部分:

本讲的机制 在 TCP 里的对应
校验和 TCP 首部的 checksum 字段
序号 TCP 的序号是「字节编号」而非「分组编号」
累积 ACK(GBN) TCP 用的正是累积 ACK
单个定时器(GBN) TCP 也只为最老的未确认段设一个定时器
缓存乱序分组(SR) TCP 接收方通常会缓存 —— 所以 TCP 是 GBN 与 SR 的混合体
重复 ACK(rdt2.2) 快速重传:收到 3 个重复 ACK 立即重传

Week 6 会在此之上补充三次握手、流量控制(接收窗口 rwnd)、拥塞控制(慢启动、拥塞避免、快速恢复)

配套练习20 题期中模拟卷 的板块四(Q17–Q20)专测本讲内容。