Skip to content
NotesComputer Networking

自顶向下的计算机网络笔记,覆盖应用层、传输层、网络层与链路层。

第三章:传输层 ​

传输层位于应用层和网络层之间。网络层提供主机到主机的通信,而传输层把这个能力扩展为 进程到进程的逻辑通信。本章围绕四条主线展开:多路复用/多路分解、可靠数据传输、流量控制、拥塞控制,并讨论互联网中的 UDP、TCP 和 QUIC。

目录 ​


3.1 传输层服务 ​

传输层提供的是运行在不同主机上的应用进程之间的逻辑通信。应用进程不需要直接处理底层网络细节,只需要通过套接字把数据交给传输层。

层次通信对象典型单位核心问题
网络层主机到主机IP 数据报如何跨网络到达目的主机
传输层进程到进程报文段 segment如何把数据交给正确进程,并提供可靠性、流量控制、拥塞控制等能力

发送端和接收端动作 ​

发送端:

  1. 从应用层接收消息。
  2. 选择并填写传输层首部字段。
  3. 形成传输层报文段。
  4. 把报文段交给 IP 层封装和发送。

接收端:

  1. 从 IP 层接收报文段。
  2. 检查传输层首部字段。
  3. 提取应用层消息。
  4. 通过套接字把消息交给正确应用进程。

TCP 与 UDP ​

互联网主要提供两种传输层协议:

协议服务主要特性
TCP可靠、有序、面向连接的字节流可靠传输、流量控制、拥塞控制、连接管理
UDP无连接、不可靠、无序的数据报服务开销小、无握手、无拥塞控制、应用可自定义可靠性

传输层不直接提供两类保证:

  • 延迟保证:不能保证某个报文段一定在指定时间内到达。
  • 带宽保证:不能保证应用一定获得某个最小速率。

一个直观类比:网络层像邮政系统,把信从一栋房子送到另一栋房子;传输层像房子里的负责人,把信分发给正确的孩子。主机是房屋,进程是孩子,应用消息是信件。

3.2 多路复用和多路分解 ​

多路复用和多路分解解决的是:同一台主机上有很多应用进程同时通信,传输层如何把数据从多个进程发出去,又如何把收到的数据交回正确进程。

方向名称作用
发送端多路复用 multiplexing从多个套接字收集数据,加上传输层首部后交给网络层
接收端多路分解 demultiplexing根据首部字段,把收到的报文段交给正确套接字

传输层依靠端口号完成分发。TCP/UDP 首部中都有源端口号和目的端口号。

UDP 的无连接多路分解 ​

UDP 套接字主要由目的 IP 和目的端口标识。接收主机收到 UDP 报文段后,只看目的端口号,把数据交给绑定该端口的套接字。

因此,不同源 IP、不同源端口发来的 UDP 报文,只要目的 IP 和目的端口相同,就会进入同一个 UDP 套接字。

text
UDP demux key = (destination IP, destination port)

TCP 的面向连接多路分解 ​

TCP 连接由四元组标识:

text
(source IP, source port, destination IP, destination port)

Web 服务器可以让很多客户端同时连接自己的 80 或 443 端口。虽然目的 IP 和目的端口相同,但源 IP 或源端口不同,因此系统可以把不同连接分发给不同 TCP 套接字。

协议多路分解依据结果
UDP目的 IP、目的端口多个发送方可进入同一个 socket
TCP源 IP、源端口、目的 IP、目的端口每条连接对应一个 socket

3.3 无连接传输:UDP ​

UDP (User Datagram Protocol) 是对 IP 的极薄封装。它提供端口号和校验和,但不提供连接建立、可靠传输、流量控制和拥塞控制。

UDP 的特点 ​

特点含义
无连接发送前不握手,每个 UDP 报文段独立处理
不可靠报文段可能丢失
无序报文段可能乱序到达
首部小UDP 首部只有 8 字节
无拥塞控制应用可以按自己的节奏发送,但也可能伤害网络公平性

UDP 适合对时延敏感、能容忍少量丢包,或者希望在应用层自行实现可靠性的场景。

常见用途:

  • DNS 查询。
  • SNMP。
  • 实时音视频。
  • QUIC / HTTP/3。
  • 应用层自定义可靠传输和拥塞控制。

UDP 报文段格式 ​

字段长度作用
source port16 bit源端口号
destination port16 bit目的端口号
length16 bitUDP 首部和数据总长度
checksum16 bit检测首部和数据中的比特错误

UDP 校验和 ​

UDP 校验和用于检测报文段传输中是否发生比特翻转。

发送方:

  1. 把 UDP 首部、UDP 数据和 IP 伪首部视为 16 bit 整数序列。
  2. 使用反码求和,把溢出的进位回绕加到低位。
  3. 对最终结果取反,放入 checksum 字段。

接收方重新计算:

检查结果含义
不匹配检测到错误
匹配未检测到错误,但仍可能存在漏检

UDP 校验和能力弱于 CRC,但足够轻量,适合传输层端到端错误检测。

3.4 可靠数据传输原则 ​

可靠数据传输 (reliable data transfer, rdt) 的目标是在不可靠信道上向上层提供“可靠、有序、不重复”的数据交付抽象。它是 TCP 可靠性的理论基础:TCP 的细节更复杂,但核心仍然是校验、序号、确认、定时器、重传和窗口。

接口可以抽象为:

函数方向含义
rdt_send(data)上层调用发送方应用要求可靠发送数据
udt_send(packet)rdt 调用下层通过不可靠信道发送分组
rdt_rcv(packet)下层通知 rdt有分组到达
deliver_data(data)rdt 交付上层可靠地把数据交给应用

可以把 rdt 看作夹在应用层和不可靠信道之间的一层状态机:

text
application
    |
rdt_send(data)
    |
reliable data transfer protocol
    |
udt_send(packet)
    |
unreliable channel

接收方向上交付数据时,必须保证三件事:

  1. 不错:损坏的数据不能交付。
  2. 不漏:丢失的数据最终要补回来。
  3. 不重:重传导致的重复分组不能重复交付。

rdt 协议的工具箱 ​

机制解决的问题基本思想
checksum比特错误接收方检测分组是否损坏
ACK正向确认接收方告诉发送方“这个分组收到了”
NAK反向确认接收方告诉发送方“这个分组坏了,请重发”
序列号重复分组接收方区分新分组和重传旧分组
定时器丢包超时未收到确认时重传
窗口低利用率允许多个分组同时在途
缓冲区乱序到达保存未能立即按序交付的分组

rdt 的演进就是逐步放松底层信道假设,并为每个新问题加入一个机制。

rdt 1.0:完全可靠信道 ​

rdt 1.0 假设底层信道不会出错、不会丢包、不会乱序。发送方只需要把数据打包后交给下层;接收方收到后直接交给上层。

角色行为
发送方rdt_send(data) 后直接 udt_send(packet)
接收方rdt_rcv(packet) 后直接 deliver_data(data)

它没有 ACK、没有重传、没有序列号。这个版本本身不实用,但作为起点能说明:可靠性复杂度完全来自底层信道的不可靠。

rdt 2.0:信道可能有比特错误 ​

rdt 2.0 假设分组可能被损坏,但不会丢失。为此需要三个机制:

机制用途
checksum接收方判断数据分组是否损坏
ACK接收方确认正确收到
NAK接收方要求发送方重传

发送方逻辑:

  1. 从上层收到数据,生成带 checksum 的分组并发送。
  2. 等待接收方反馈。
  3. 收到 ACK,说明本分组成功,准备发送下一个。
  4. 收到 NAK,说明分组损坏,重传当前分组。

接收方逻辑:

  1. 收到分组后检查 checksum。
  2. 若分组未损坏,交付数据并发送 ACK。
  3. 若分组损坏,丢弃数据并发送 NAK。

rdt 2.0 是 停止-等待协议:发送方每次只能有一个未确认分组在途。

rdt 2.0 的致命问题是:它默认 ACK/NAK 不会损坏。现实中控制报文也可能出错。如果发送方收到一个损坏的 ACK/NAK,它不知道接收方到底收到了还是没收到。直接重传可能导致重复交付;直接发送下一个又可能导致丢数据。

rdt 2.1:ACK/NAK 也可能损坏 ​

rdt 2.1 引入 序列号。由于仍是停止-等待协议,发送方最多只有一个分组在途,所以只需要 1 bit 序列号:0 和 1 交替使用。

发送方维护两个主要状态:

状态含义
等待上层数据,准备发送 seq=0下一个新分组使用序号 0
等待 ACK/NAK for seq=0seq=0 分组已发出,等待反馈
等待上层数据,准备发送 seq=1下一个新分组使用序号 1
等待 ACK/NAK for seq=1seq=1 分组已发出,等待反馈

接收方也维护期望序号:

收到的分组接收方动作
未损坏,序号等于期望序号交付数据,发送 ACK,切换期望序号
未损坏,但序号不是期望序号说明是重复分组,不交付,重新 ACK 上次正确分组
损坏发送 NAK

序列号解决了重复分组问题。即使 ACK 损坏导致发送方重传,接收方也能通过序号发现这是旧分组,从而不重复交付。

rdt 2.2:无 NAK 协议 ​

rdt 2.2 去掉 NAK,只使用 ACK。它的思想是:如果接收方收到损坏分组,就重新发送“最后一个正确收到分组”的 ACK。这个重复 ACK 对发送方来说等价于 NAK。

例如接收方期望 seq=1,但收到损坏分组,或者收到重复的 seq=0,则发送 ACK(0)。发送方如果正在等待 ACK(1),却收到 ACK(0),就知道 seq=1 没有被正确接收,于是重传 seq=1。

这很重要,因为 TCP 也采用“ACK-only”的思想:TCP 没有显式 NAK,而是通过重复 ACK 暗示缺失数据。

rdt 3.0:信道可能丢包 ​

rdt 3.0 进一步假设:数据分组和 ACK 都可能丢失。仅靠 ACK 不够,因为如果分组丢了,接收方根本不会回 ACK,发送方会永远等待。

新机制是 定时器:

  1. 发送方发送分组后启动定时器。
  2. 如果定时器到期前收到正确 ACK,停止定时器,发送下一个分组。
  3. 如果超时还没收到 ACK,发送方假定分组或 ACK 丢失,重传当前分组。

超时重传可能产生重复分组。例如原分组没有丢,只是 ACK 回来得慢,发送方过早超时并重传。序列号仍然负责让接收方识别重复分组。

rdt 3.0 的典型场景:

场景结果如何处理
数据分组丢失接收方无响应发送方超时重传
ACK 丢失发送方不知道接收方已收到发送方超时重传,接收方用序号丢弃重复数据
ACK 延迟可能触发不必要重传序号防止重复交付
数据损坏接收方不交付接收方发送重复 ACK 或等价反馈,发送方重传

到 rdt 3.0 为止,可靠性已经成立:出错、丢包、重复都能处理。但它仍然一次只发一个分组,性能很差。

停止-等待协议的本质 ​

rdt 2.x 和 rdt 3.0 都是停止-等待协议。其不变量是:

text
发送方最多只有 1 个未确认分组在网络中

优点是状态简单,1 bit 序列号就够;缺点是 RTT 大时链路利用率极低。

rdt 3.0 的性能问题 ​

停止-等待协议的发送方利用率近似为:

Usender=L/RRTT+L/R

其中 L 是分组长度,R 是链路速率。若 RTT 很大、发送时间 L/R 很小,发送方绝大多数时间都在等待 ACK,链路利用率会很低。

课件中的例子得到:

Usender=0.00830.008≈0.00027

这说明可靠性机制正确还不够,协议还必须能有效利用链路容量。

流水线协议 ​

流水线协议放松停止-等待限制,允许发送方同时有多个“在途”但尚未确认的分组。

text
停止-等待:send pkt0 -> wait ACK0 -> send pkt1 -> wait ACK1
流水线:  send pkt0, pkt1, pkt2, ... -> ACKs come back later

它需要:

  • 更大的序列号空间。
  • 发送方缓冲未确认分组。
  • 接收方可能需要缓冲乱序分组。
  • 窗口机制控制最多有多少分组在途。

流水线协议的两个经典实现是 Go-Back-N 和 Selective Repeat。

协议接收方是否缓存乱序分组ACK 方式重传方式
Go-Back-N通常不缓存累积 ACK丢失点及其之后全部重传
Selective Repeat缓存单独 ACK只重传未确认分组

Go-Back-N ​

Go-Back-N (GBN) 的发送方允许最多 N 个未确认分组在途。

发送方:

  • 维护大小为 N 的发送窗口。
  • ACK 是累积确认,ACK(n) 表示序号 ≤n 的分组都已正确收到。
  • 只为最老的未确认分组设置定时器。
  • 若分组 n 超时,则重传 n 及其之后窗口内所有分组。

接收方:

  • 只按序接收。
  • 收到乱序分组时通常丢弃。
  • 对已按序收到的最高序号发送重复 ACK。
  • 只需记住 rcv_base 或 expectedseqnum。

GBN 的窗口可以理解成三个区域:

text
[ 已确认 ][ 已发送未确认 ][ 可发送但未发送 ][ 暂不可用 ]
          base          nextseqnum       base+N

例子:窗口大小 N=4,分组 0、1、2、3 已发送。如果分组 2 丢失,接收方可能收到 3,但因为 2 缺失,3 是乱序分组,会被丢弃并重复 ACK 1。发送方等到 2 超时后,需要重传 2、3,以及窗口中更高序号的未确认分组。

GBN 的接收方简单,但代价是:一个分组丢失会导致它后面许多已经到达过的分组被浪费。

Selective Repeat ​

Selective Repeat (SR) 只重传真正丢失或出错的分组。

发送方:

  • 对每个未确认分组单独维护定时器。
  • 收到某个分组的 ACK 后只标记该分组已确认。
  • 窗口基址推进到最小未确认序号。

接收方:

  • 对每个正确收到的分组单独 ACK。
  • 可以缓存乱序分组。
  • 当缺口补齐后,把连续有序数据交给上层。

SR 的窗口推进更细:

事件发送方行为接收方行为
上层给数据,窗口有空位发送下一个序号分组,启动该分组计时器无
收到 ACK(n)标记 n 已确认;若 n 是窗口基址,滑动到下一个未确认分组无
分组 n 超时只重传 n无
收到窗口内未损坏分组 n无发送 ACK(n),若乱序则缓存
收到窗口左侧旧分组 n无重新发送 ACK(n),避免发送方误以为 ACK 丢失
收到窗口外无关分组无忽略

SR 的效率更高,但接收方和发送方状态更复杂。尤其要注意循环序列号导致的旧包/新包混淆。

如果序列号只有 0,1,2,3,窗口大小却是 3,那么接收方在某些情况下无法判断一个新到达的 0 是“新一轮的 0”,还是“上一轮超时重传的旧 0”。为了避免这个歧义,通常要求:

WT+WR≤2n

若发送窗口和接收窗口大小相等,则常写作:

W≤2n−1

其中 n 是序列号 bit 数。

小结:rdt 机制如何对应到 TCP ​

rdt 概念TCP 中的体现
checksumTCP 首部校验和
序列号TCP 字节序列号
ACKTCP 累积确认
定时器TCP 超时重传
重复 ACKTCP 快速重传信号
流水线TCP 发送窗口
接收缓存TCP 接收缓冲区和乱序缓存
窗口大小同时受流量控制 rwnd 和拥塞控制 cwnd 限制

3.5 面向连接的传输:TCP ​

TCP 是面向连接的、可靠的、有序的字节流协议。它的服务不是“消息流”,而是 字节流:应用写入的边界不会天然保留。

TCP 概述 ​

特性含义
点对点一个发送方,一个接收方
可靠有序字节按序、无缺失、无重复地交给应用
全双工同一连接中两个方向都可同时传输
面向连接数据交换前通过握手初始化状态
流水线允许多个未确认字节在途
累积 ACKACK 表示期望收到的下一个字节
流量控制发送方不能淹没接收方缓冲区
拥塞控制发送方根据网络拥塞调整速率

TCP 段结构 ​

TCP 首部包含:

字段作用
source / destination port标识发送和接收进程
sequence number本段数据第一个字节的编号
acknowledgement number期望从对方收到的下一个字节
header lengthTCP 首部长度
flagsACK、RST、SYN、FIN、CWR、ECE、URG、PSH 等控制位
receive window接收方愿意接收的字节数,用于流量控制
checksum互联网校验和
urgent pointer紧急数据指针
optionsMSS、窗口扩大、时间戳、SACK 等可选项
data应用数据

TCP 的序列号按 字节 编号,不按段编号。

序列号与确认号 ​

序列号是本段数据中第一个字节在字节流中的编号。ACK 号是接收方期望收到的下一个字节编号,因此 TCP ACK 是累积确认。

例如:

text
A -> B: Seq=42, ACK=79, data='C'
B -> A: Seq=79, ACK=43, data='C'
A -> B: Seq=43, ACK=80

这表示 A 发出的字节 42 已被 B 收到,B 下一步期望字节 43;B 回显的字节 79 又被 A 确认,A 下一步期望字节 80。

TCP 标准没有强制规定接收方如何处理乱序段,具体实现可以选择缓存或丢弃,但实际 TCP 通常会缓存并配合 SACK 等机制。

RTT 估计与超时 ​

TCP 超时值必须大于 RTT,但 RTT 会动态变化:

  • 超时太短:会过早重传。
  • 超时太长:对丢包反应太慢。

TCP 用 SampleRTT 测量某个段从发送到 ACK 返回的时间,通常忽略重传样本。EstimatedRTT 使用指数加权移动平均:

EstimatedRTT=(1−α)⋅EstimatedRTT+α⋅SampleRTT

典型取值:

α=0.125

RTT 偏差也用 EWMA 估计:

DevRTT=(1−β)⋅DevRTT+β⋅|SampleRTT−EstimatedRTT|

典型取值:

β=0.25

超时间隔设置为:

TimeoutInterval=EstimatedRTT+4⋅DevRTT

TCP 发送方简化逻辑 ​

收到应用数据:

  1. 创建 TCP 段,序列号为该段第一个字节编号。
  2. 把段交给 IP。
  3. 若当前没有计时器运行,启动计时器。

收到 ACK:

  1. 如果 ACK 确认了新的数据,更新 SendBase。
  2. 如果仍有未确认段,重新启动计时器。
  3. 如果没有未确认段,停止计时器。

超时:

  1. 重传最小序列号的未确认段。
  2. 重启计时器。

TCP 接收方 ACK 生成 ​

接收事件TCP 接收方行为
按序段到达,且之前数据都已确认延迟 ACK,最多等待约 500 ms
按序段到达,且已有一个 ACK 等待发送立即发送累积 ACK
乱序段到达,检测到缺口立即发送重复 ACK,指明下一个期望字节
到达段部分或完全填补缺口若从缺口低端开始,立即发送 ACK

重复 ACK 是快速重传的重要信号。

快速重传 ​

如果发送方收到同一数据的 3 个重复 ACK,说明某个段之后的多个段已经到达,但那个段缺失。发送方不必等超时,而是立即重传最小未确认序列号的段。

text
3 duplicate ACKs -> fast retransmit missing segment

快速重传可以显著缩短丢包恢复时间。

TCP 流量控制 ​

流量控制解决的是:发送方不要把接收方缓冲区塞爆。它不同于拥塞控制,拥塞控制关注网络内部是否过载。

接收方在 TCP 首部的 receive window 字段中通告可用缓冲区空间,记为 rwnd。发送方限制未确认的在途数据量:

LastByteSent−LastByteAcked≤rwnd

这样即使应用程序从接收缓冲区读取数据较慢,发送方也不会无限制地继续注入数据。

TCP 连接管理 ​

连接建立前,双方需要:

  • 确认彼此愿意建立连接。
  • 协商和初始化连接状态,例如初始序列号。
  • 避免旧的重复连接请求造成半打开连接或重复数据问题。

两次握手在存在延迟、丢失、重传和乱序的网络中不可靠,可能产生半打开连接或错误接收旧数据。因此 TCP 使用三次握手。

三次握手:

  1. 客户端选择初始序列号 x,发送 SYN=1, Seq=x。
  2. 服务器选择初始序列号 y,回复 SYN=1, Seq=y, ACK=x+1。
  3. 客户端回复 ACK=y+1,连接进入 established 状态。

连接关闭:

  • 每个方向独立关闭。
  • 一方发送 FIN=1 表示自己不再发送。
  • 对方 ACK 该 FIN。
  • 对方也关闭时再发送自己的 FIN。
  • 同时 FIN 交换也可以被正确处理。

3.6 拥塞控制原则 ​

拥塞是指网络中太多发送方以太快速度注入太多数据,超过网络处理能力。表现为:

  • 路由器队列变长,时延增加。
  • 缓冲区溢出,分组丢失。
  • 重传增加,进一步加重负载。

拥塞控制和流量控制不同:

机制控制对象问题
流量控制一个发送方和一个接收方发送方太快,接收方缓冲区吃不消
拥塞控制多个发送方和网络内部总注入速率太高,路由器和链路吃不消

拥塞的代价 ​

课件用几个场景说明拥塞的代价:

  1. 无限缓冲单路由器:吞吐量有上限,随着输入速率接近容量,排队时延急剧增加。
  2. 有限缓冲和重传:丢包导致重传,重传消耗链路容量,有效吞吐下降。
  3. 过早超时:原分组和重传副本都可能成功到达,不必要副本浪费容量。
  4. 多跳路径:某个下游链路丢包时,已经在上游链路和缓冲区消耗的资源全部浪费。

拥塞带来的核心结论:

  • 吞吐量不能超过链路容量。
  • 接近容量时,时延会快速增加。
  • 丢失和重传会降低有效吞吐量。
  • 不必要的重传副本进一步浪费容量。
  • 在多跳路径中,下游丢包会浪费上游已经投入的传输资源。

两类拥塞控制方法 ​

方法思想例子
端到端拥塞控制网络不显式反馈,发送方根据丢包、延迟推断拥塞传统 TCP
网络辅助拥塞控制路由器向端系统显式反馈拥塞信息或速率建议ECN、ATM、DECbit

TCP 主要采用端到端方法,同时现代网络也常部署 ECN 这样的网络辅助机制。

3.7 TCP 拥塞控制 ​

TCP 拥塞控制的核心变量是拥塞窗口 cwnd。发送方同时受到 cwnd 和接收窗口 rwnd 限制。

简化地说:

LastByteSent−LastByteAcked<cwnd

TCP 发送速率近似为:

TCP rate≈cwndRTT

cwnd 根据网络反馈动态调整。

AIMD ​

经典 TCP 使用 AIMD:

阶段行为
Additive Increase每个 RTT 大约增加 1 MSS
Multiplicative Decrease检测到丢包时把发送速率减半

这种机制形成锯齿状速率曲线:不断探测可用带宽,发现拥塞后降低速率。

丢包信号的处理:

  • 三次重复 ACK:TCP Reno 通常把窗口减半。
  • 超时:TCP Tahoe 把窗口降到 1 MSS。

慢启动 ​

连接刚开始时,TCP 不知道可用带宽,因此从较小窗口开始:

  • 初始 cwnd = 1 MSS。
  • 每收到一个 ACK,cwnd 增加 1 MSS。
  • 因此每个 RTT 大约翻倍,呈指数增长。

慢启动名字叫“慢”,但增长速度其实很快。它只是相对直接发送大量数据而言从小窗口起步。

从慢启动到拥塞避免 ​

TCP 使用阈值 ssthresh 决定何时从指数增长切换到线性增长。

规则:

  • 当 cwnd < ssthresh:慢启动,指数增长。
  • 当 cwnd >= ssthresh:拥塞避免,线性增长。
  • 发生丢包时:ssthresh = cwnd / 2。

典型状态包括:

状态行为
slow startACK 到来时快速增加 cwnd
congestion avoidance每 RTT 约增加 1 MSS
fast recovery三次重复 ACK 后快速重传并部分恢复窗口

TCP CUBIC ​

TCP CUBIC 是 Linux 默认并广泛部署的拥塞控制算法。它尝试比经典 AIMD 更高效地探测可用带宽。

直觉:

  • 记录发生丢包时的窗口 Wmax。
  • 丢包后窗口减小。
  • 距离 Wmax 远时增长更快。
  • 接近 Wmax 时增长变慢,谨慎探测。
  • 超过 Wmax 后再逐渐加速寻找新的可用带宽。

CUBIC 更适合高速长距离网络。

基于延迟的拥塞控制 ​

丢包驱动的 TCP 往往会把瓶颈队列填满,导致高 RTT。基于延迟的方法试图让管道“刚好满,但不过满”。

核心思路:

  • 记录最小 RTT,记为 RTTmin,近似代表无拥塞时延。
  • 根据当前 cwnd / RTTmin 估计无拥塞吞吐。
  • 根据实际测得吞吐和 RTT 判断是否已经出现排队。
  • 若接近无拥塞状态,增加窗口。
  • 若实际吞吐明显低于无拥塞估计,减少窗口。

BBR 等算法体现了这种思路。

TCP 吞吐量 ​

忽略慢启动,假设窗口在 W/2 到 W 之间锯齿变化,则平均窗口约为:

34W

平均吞吐量近似为:

avg TCP throughput=3W4RTT

对于长距离高速链路,传统 TCP 要达到高吞吐需要极低丢包率。例如 1500 字节段、100 ms RTT、目标 10 Gbps,需要约 83,333 个在途段,能容忍的丢包率极低。

ECN ​

ECN (Explicit Congestion Notification) 是网络辅助拥塞控制。

过程:

  1. 路由器在 IP 首部 ECN 位中标记拥塞,而不是直接丢包。
  2. 接收端收到带拥塞标记的数据报。
  3. 接收端在 TCP ACK 中设置 ECE 位通知发送方。
  4. 发送方降低发送速率,并可用 CWR 位表示已响应拥塞。

ECN 让网络可以在丢包前发出拥塞信号。

TCP 公平性 ​

公平性目标:如果 K 条 TCP 连接共享瓶颈链路容量 R,每条连接平均应获得:

RK

在理想条件下,AIMD 会推动连接趋向公平共享。这些理想条件包括相同 RTT、固定会话数、都处在拥塞避免阶段。

实际中公平性会被破坏:

  • UDP 应用可能不遵守 TCP 式拥塞控制。
  • 应用可以开启多个并行 TCP 连接,抢占更多带宽。
  • 不同 RTT 的 TCP 连接获得的份额可能不同。

3.8 传输层功能的演变 ​

TCP 和 UDP 是互联网长期使用的核心传输协议,但不同场景推动了传输层功能不断演进。

场景挑战
长肥管道在途数据很多,一次丢包会让管道明显变空
无线网络丢包可能来自链路噪声和移动性,但 TCP 会误认为拥塞
长时延链路RTT 很大,反馈慢
数据中心网络对低时延和高吞吐都敏感
后台流量希望低优先级传输,不影响交互流量

一种重要趋势是:把一部分传输层功能移动到应用层,并基于 UDP 部署。这使新协议更容易穿过已有网络设备,也更容易快速迭代。

QUIC ​

QUIC (Quick UDP Internet Connections) 是基于 UDP 的应用层传输协议,是 HTTP/3 的基础。

协议栈对比:

传统 HTTP/2HTTP/3
HTTP/2 -> TLS -> TCP -> IPHTTP/3 -> QUIC -> UDP -> IP

QUIC 在应用层实现了很多类似 TCP 的能力:

  • 可靠数据传输。
  • 丢失检测。
  • 拥塞控制。
  • 连接建立。
  • 加密和认证。
  • 多路复用应用级流。

QUIC 的优势 ​

  1. 连接建立更快
    TCP + TLS 往往需要串行握手;QUIC 把可靠性、拥塞控制、认证和加密状态整合在一起,通常一个 RTT 内建立状态。

  2. 减少队头阻塞
    在 TCP 中,一个丢失的字节会阻塞后续字节交付,导致同一连接上的多个 HTTP 流都受影响。QUIC 在单个连接上提供多个独立可靠流,一个流丢包不会阻塞其他流的应用层交付。

  3. 更容易演进
    QUIC 运行在 UDP 之上,很多中间设备只看到 UDP 流量。协议逻辑在应用层实现,升级速度比修改内核 TCP 和网络设备更快。

QUIC 说明:传输层的核心思想没有消失,而是被重新组合到了更容易部署的层次中。

3.9 本章小结 ​

本章的核心问题是:如何在不可靠的网络层之上,为应用进程提供可用的端到端传输服务?

需要掌握的主线:

  1. 传输层提供进程到进程的逻辑通信,网络层提供主机到主机的逻辑通信。
  2. 多路复用和多路分解依靠端口号和套接字完成。
  3. UDP 是无连接、不可靠、低开销的传输协议,适合实时、简单查询和应用自定义传输逻辑。
  4. 可靠数据传输依靠校验和、ACK/NAK、序列号、定时器和重传。
  5. 停止-等待协议正确但效率低,流水线协议通过窗口提高链路利用率。
  6. GBN 使用累积 ACK 和批量回退重传;SR 使用单独 ACK、缓存乱序分组和选择性重传。
  7. TCP 提供可靠有序字节流,使用序列号、累积 ACK、RTT 估计、超时重传和快速重传。
  8. TCP 流量控制通过 rwnd 防止接收方缓冲区溢出。
  9. TCP 三次握手建立连接,FIN/ACK 机制关闭连接。
  10. 拥塞控制关注网络内部过载,不同于只保护接收方的流量控制。
  11. TCP 拥塞控制使用 cwnd、慢启动、拥塞避免、快速恢复、AIMD 等机制调整发送速率。
  12. CUBIC、基于延迟的方法、ECN 和 QUIC 体现了传输层功能在现代网络中的持续演进。

下一章开始进入网络核心:网络层如何转发数据报,以及路由器内部和控制平面如何工作。