计算机网络第七版·第三章 运输层
思路导图: https://www.mubu.com/doc/17DpcaeLvoA
一.概述
运输层是网络协议栈中的核心层,它为运行在不同主机上的应用进程之间提供逻辑通信功能。这意味着,尽管主机可能相隔千里,物理连接复杂,但应用进程之间仿佛直接相连。
1.1 运输层与网络层的关系
- 网络层提供的是主机到主机的逻辑通信。以寄信为例,网络层协议(如 IP)就像邮政服务,负责将信件从一个家庭(主机)送到另一个家庭。
- 运输层提供的是进程到进程的逻辑通信。运输层协议(如 TCP 和 UDP)就像家庭里的“收发员”,负责将信件从一个家庭成员(进程)发送给另一个家庭成员,并在信件中添加自己的控制信息。
1.2 因特网运输层概述
因特网提供了两种主要的运输层协议,每种协议提供不同的服务模型:
- UDP (User Datagram Protocol) - 用户数据报协议
- 服务模型:一种不可靠、无连接的服务。
- 主要功能:仅提供进程到进程的数据交付和差错检查。它不保证报文段的交付、按序交付或数据完整性。
- 特点:速度快,简单高效,应用程序可以以任何速率发送数据,不会进行流量调节。
- TCP (Transmission Control Protocol) - 传输控制协议
- 服务模型:一种可靠、面向连接的服务。
- 主要功能:
- 可靠数据传输:通过使用序号、确认和定时器等机制,确保数据能正确、按序地从发送进程交付给接收进程。
- 拥塞控制:通过调节发送速率,防止网络链路因过多流量而拥塞,确保所有连接公平地共享带宽。
- 特点:复杂但功能强大,将不可靠的 IP 服务转变为可靠的进程间数据传输服务。
两个术语:
- 报文段(Segment):本书将 TCP 和 UDP 的运输层分组都统称为报文段。
- 数据报(Datagram):本书将此术语保留给网络层分组,以避免与 UDP 混淆。
二.多路复用与多路分解
1.核心概念
- 多路复用(Multiplexing):在源主机上,运输层从多个套接字(sockets)中收集应用进程的数据块,为每个数据块加上首部信息,形成运输层报文段,然后将报文段交给网络层。
- 多路分解(Demultiplexing):在目的主机上,运输层从网络层接收报文段,通过检查报文段首部中的特定字段,将报文段的数据交付给正确的套接字,进而传递给对应的应用程序进程。
2.端口号
为了实现多路复用与多路分解,运输层在报文段首部使用了端口号。
- 端口号是一个 16 比特的数字,范围在 0 到 65535 之间。
- 周知端口号(0-1023)被保留给 HTTP (80)、FTP (21) 等知名应用层协议使用。
- 非周知端口号(1024-65535)通常由客户端动态分配。
3.UDP 的多路复用与多路分解
- 标识符:一个 UDP 套接字由一个二元组唯一标识:
(目的 IP 地址, 目的端口号)
。 - 工作方式:当 UDP 报文段到达主机时,运输层只检查目的端口号,并将报文段交付给与该端口号绑定的套接字。
- 重要特点:来自不同源 IP 地址或源端口号的 UDP 报文段,只要它们有相同的目的 IP 地址和目的端口号,就会被定向到同一个套接字。
4.TCP 的多路复用与多路分解
- 标识符:一个 TCP 套接字由一个四元组唯一标识:
(源 IP 地址, 源端口号, 目的 IP 地址, 目的端口号)
。 - 工作方式:当 TCP 报文段到达主机时,运输层需要检查这四个值,才能将报文段精确地定向到对应的套接字。
- 重要特点:与 UDP 不同,即使两个 TCP 报文段的目的 IP 和端口号相同,如果它们的源 IP 或源端口号不同,它们也会被定向到不同的套接字。一个 Web 服务器可以同时处理来自不同客户端的多个 HTTP 连接,每个连接都有一个由四元组标识的独立套接字。
三.无连接运输:UDP
(1)UDP:最简化的无连接传输协议
UDP (User Datagram Protocol) 是一种定义在 RFC 768 中的、极简的传输层协议。它几乎没有在 IP 协议的基础上增加功能,主要作用是提供最基础的复用/分解服务,以及少量的差错检测。
工作原理:UDP 从应用进程接收数据,然后附加源和目的端口号等简单首部字段,将数据打包成报文段后直接交给网络层。网络层将其封装进 IP 数据报,尽力送达接收主机。由于发送前双方不进行任何“握手”,因此 UDP 被称为无连接的协议。
(2)为何选择 UDP 而不是 TCP?
尽管 TCP 提供了可靠的数据传输服务,但许多应用开发者更倾向于使用 UDP,主要原因在于:
- 精细的应用层控制:UDP 不像 TCP 那样有拥塞控制机制。这使得应用可以更自由地决定何时、发送多少数据,特别适合对传输速率有严格要求、且能容忍少量数据丢失的实时应用(如网络电话、视频会议)。
- 无连接建立时延:UDP 无需像 TCP 那样进行耗时的“三次握手”来建立连接,可以立即开始数据传输。这对于像 DNS 这种追求低延迟的应用至关重要。
- 无连接状态:UDP 不需要维护连接状态(如缓存、拥塞控制参数等),这使得服务器能更高效地处理大量的并发客户端请求。
- 分组首部开销小:UDP 的报文段首部只有 8 字节,远小于 TCP 的 20 字节,节省了传输开销。
(3)UDP 的局限性及应用
UDP 提供了差错检测(通过检验和字段),但不提供差错恢复。当检测到错误时,受损的报文段通常会被丢弃。
尽管如此,UDP 在许多重要应用中扮演着关键角色:
- DNS 和 SNMP (网络管理):因其对低延迟和简单性的需求,通常使用 UDP。
- 实时多媒体应用(如流式音视频、网络电话):由于这类应用能容忍少量数据丢失,但对延迟敏感,因此更倾向于使用 UDP。
值得注意的是,由于 UDP 缺乏拥塞控制,如果被不加限制地使用,可能会导致网络拥塞,甚至影响到 TCP 会话的性能。不过,应用开发者可以在应用层自己构建可靠性机制,从而在享受 UDP 传输速度的同时,实现可靠通信,例如谷歌浏览器中的 QUIC协议就是在 UDP 上实现了可靠性。
(4)UDP 报文段结构
UDP 报文段的结构非常简单,由两部分组成:首部和数据字段。
- 数据字段:这部分用于承载应用层数据。例如,对于 DNS 应用,数据字段可以是查询或响应报文;对于流式音频应用,则填充音频采样数据。
- 首部:UDP 的首部只有 4 个字段,每个字段占用 2 个字节,总共 8 个字节。这 4 个字段分别是:
- 源端口号:用于标识发送数据的应用进程。
- 目的端口号:用于使接收主机能将数据报文段交付给正确的应用进程,实现分解功能。
- 长度:指明整个 UDP 报文段(包括首部和数据)的字节数。由于数据字段的长度是可变的,所以需要一个明确的长度字段。
- 检验和:用于差错检测,以确定报文段在传输过程中比特位是否发生变化。接收方通过检验和来检查报文段的完整性。
(5)UDP 检验和:差错检测功能
UDP 检验和的主要作用是进行差错检测,以确保报文段在从源主机到目的主机的传输过程中,其数据没有发生任何比特错误。
如何计算和验证
- 发送方:将报文段中的所有 16 比特字相加(求和过程中产生的溢出进行回卷处理),然后对最终的和进行反码运算。得到的结果就是检验和,并被放入 UDP 报文段的首部字段中。
- 接收方:将接收到的报文段中所有的 16 比特字(包括检验和)相加。
- 如果最终结果是全为 1 (即
1111111111111111
),则表明报文段在传输过程中没有出现差错。 - 如果最终结果中的任何一个比特为 0,则表明报文段已损坏。
为什么需要端到端差错检测?
尽管许多链路层协议(如以太网)也提供了差错检测,但 UDP 仍然在传输层提供了检验和,这是因为:
- 如果最终结果是全为 1 (即
- 链路不一定可靠:无法保证源和目的主机之间的所有链路都提供差错检测服务。
- 路由器内存可能出错:即使报文段在链路上正确传输,也可能在路由器内存中引入比特错误。
因此,为了确保数据传输的完整性,必须在端到端的基础上提供差错检测。这体现了网络设计的端到端原则:如果某个功能必须在高级别(如传输层)实现,那么在低级别(如链路层)提供该功能可能是多余或无价值的。
需要注意的是,UDP 检验和只能检测错误,但无法恢复。当检测到错误后,UDP 的某些实现会直接丢弃受损的报文段,而另一些则会将其交付给应用并发出警告。
四.可靠数据传输原理
可靠数据传输(Reliable Data Transfer,简称 RDT)是计算机网络中最核心的问题之一。它旨在实现一个抽象的理想服务:数据能够通过一条可靠信道进行传输,即数据既不损坏也不丢失,且所有数据都按发送顺序交付。这正是 TCP 协议向应用层提供的服务模型。
本节讨论的重点是单向数据传输(从发送端到接收端)。
4.1 构造可靠数据传输协议
可靠数据传输(RDT)是计算机网络中最基础也最重要的问题之一,其核心目标是在不可靠的底层信道上,为上层应用提供一个可靠、有序且无损的数据传输服务。这与 TCP 协议向其应用层提供的服务模型完全一致。
为了实现这一目标,我们需要逐步构建和完善协议,以应对信道中可能出现的各种问题。
(1) 经完全可靠信道的协议:rdt1.0
这是协议的起点,它假设底层信道是完美无缺的,数据既不会丢失也不会损坏,且总是按序到达。
- 工作机制:
- 发送方:只有一个状态。当它收到上层应用的数据后,会立即打包成一个分组,并通过将其发送出去。
- 接收方:也只有一个状态。当它从底层信道收到分组后,会从中提取数据并立即交付给上层应用。
- 特点:这个协议非常简单,没有引入任何额外机制,因为在这种理想环境下,它们都是不必要的。发送方和接收方都不需要进行反馈或重传。
(2) 经具有比特差错信道的协议:rdt2.0
现实中的信道不完美,数据在传输过程中可能会因噪声等原因而出现比特错误。rdt2.0 协议正是为了解决这个问题而设计的。
- 核心思想:借鉴人类口头交流中的“确认”和“重说一遍”机制,引入了 ARQ (自动重传请求) 协议。
- 新增机制:
- 差错检测:通过在分组中添加检验和(Checksum)字段,接收方可以检测出分组中的比特错误。
- 接收方反馈:接收方会向发送方发送两种控制报文:
- ACK (肯定确认):表示分组已正确接收。
- NAK (否定确认):表示分组已损坏,需要重传。
- 重传:当发送方收到 NAK 时,会重传上一个分组。
- 协议状态:
- 发送方:有两个状态。一个用于等待上层数据,另一个用于在发送分组后,等待接收方的 ACK 或 NAK 响应。
- 接收方:仍只有一个状态,根据收到的分组是否损坏,决定发送 ACK 或 NAK。
- 停等协议:由于发送方在收到对当前分组的确认前,不会发送下一个新分组,这种工作模式被称为停等(stop-and-wait)协议。
(3) 应对 ACK/NAK 丢失或损坏的协议:rdt2.1 和 rdt2.2
rdt2.0 存在一个致命缺陷:如果 ACK 或 NAK 本身在传输中损坏或丢失,发送方无法得知接收方的真实状态。
- 解决方案:引入分组序号。发送方为每个分组分配一个唯一的序号(对于停等协议,使用 0 和 1 交替即可)。接收方通过检查序号来判断收到的分组是新的还是旧的(即重复的)。
- rdt2.1:在 rdt2.0 的基础上,为数据分组添加了序号,接收方也会根据序号发送相应的 ACK/NAK,发送方则根据收到的序号来决定是否重传。
- rdt2.2:是 rdt2.1 的一个改进版本,它用冗余 ACK 代替了 NAK。当接收方收到一个损坏的分组时,它会发送一个对上一个正确接收的分组的 ACK。发送方如果连续收到两个相同的 ACK,就知道之前的分组已经丢失或损坏了,从而触发重传。这种方式在很多现代协议中被采用。
(4) 经具有丢包信道的协议:rdt3.0
这是最接近现实的协议版本,它处理除了比特差错外,分组还可能丢失的情况。
- 核心思想:如果发送方在一段时间内没有收到 ACK,就假定分组已丢失,并进行重传。
- 新增机制:引入定时器。
- 启动定时器:每当发送方发送一个分组时,都会启动一个定时器。
- 超时重传:如果在定时器超时后仍未收到相应的 ACK,发送方就会重传该分组。
- 停止定时器:当发送方收到正确的 ACK 时,会终止定时器。
- 冗余问题:定时器可能会过早超时,导致发送方重传一个实际上并未丢失的分组,产生冗余数据分组。但幸运的是,rdt2.2 中引入的分组序号机制可以完美解决这个问题:接收方可以识别并丢弃重复的分组。
- 别名:由于该协议中分组序号在 0 和 1 之间交替,rdt3.0 也常被称为比特交替协议。
通过将检验和、序号、定时器以及肯定/否定确认等多种机制结合起来,我们最终构建了一个在不可靠信道上也能提供可靠服务的强大协议。
4.2 流水线可靠数据传输协议
rdt3.0 协议虽然在功能上是正确的,但其停等工作方式导致了极低的性能和网络利用率,尤其是在高速、长距离网络中。
(1)停等协议的性能瓶颈
以美国东西海岸的两个主机为例,即使链路带宽高达 1 Gbps,一个 1000 字节的分组从发送到收到确认的整个往返时间(RTT)约为 30 毫秒。然而,实际用于发送数据的时间仅为 8 微秒(L/R)。这意味着,在大部分时间内,发送方都处于空闲等待状态,导致其利用率极低(不到 0.03%),有效吞吐量远低于链路理论带宽。
这种“停等”的低效模式,严重限制了底层网络硬件所能提供的能力。
(2)流水线技术的引入
为了解决这一问题,流水线技术应运而生。其核心思想是:允许发送方在收到确认之前,连续发送多个分组,而无需停下来等待。这些分组就像是填充到了一条生产线中,从而大大提高了发送方的利用率和网络的吞吐量。
流水线技术对协议设计产生了以下影响:
- 增加序号范围:为了区分在传输中的不同分组,协议必须使用更大的序号范围,而不仅仅是 0 和 1。
- 缓存机制:
- 发送方必须能缓存所有已发送但尚未得到确认的分组,以便在需要时进行重传。
- 接收方可能也需要缓存正确接收但尚未按序交付给上层的分组。
- 复杂的差错恢复:处理丢失、损坏或延迟过大的分组变得更加复杂。
为了应对这些挑战,出现了两种主要的流水线差错恢复协议:回退 N 步(Go-Back-N, GBN)和选择重传(Selective Repeat, SR)。
4.3 回退N步
回退 N 步 (Go-Back-N, GBN) 是一种流水线可靠数据传输协议,它通过允许多个分组在未确认的情况下连续发送,显著提高了网络利用率。然而,这种发送并非无限制的,发送方在任何时候都只能有不超过 N 个未确认的分组。这里的 N 被称为窗口长度,因此 GBN 协议也被称为滑动窗口协议。
(1)GBN 发送方
GBN 发送方维护一个有序的分组序号范围,可分为四个部分:
- 已发送并已确认:序号范围为
。 - 已发送但未确认:序号范围为
。这部分分组构成了发送方的窗口。 - 可立即发送:序号范围为
。如果有上层数据可用,可立即发送这些分组。 - 不可用:序号大于或等于
的分组暂时不能发送,直到窗口向前滑动。
发送方主要响应三种事件:
- 上层调用:当上层有新数据需要发送时,发送方会检查窗口是否已满。如果窗口未满,发送方会创建分组并立即发送,然后更新
nextseqnum
变量。如果窗口已满,发送方通常会拒绝数据或将其缓存,等待窗口腾出空间。 - 收到 ACK:GBN 协议使用累积确认。一个对序号
n
的 ACK 意味着接收方已经正确接收了包括n
在内的所有序号小于或等于n
的分组。当发送方收到这样的 ACK 时,会更新base
变量,使窗口向前滑动。 超时事件:GBN 发送方只使用一个定时器,该定时器用于最早的未确认分组。一旦定时器超时,发送方会立即重传所有已发送但尚未被确认的分组。这正是“回退 N 步”名称的由来——它会回退到
base
处,重新发送整个窗口内的分组。(2)GBN 接收方
GBN 接收方的行为相对简单。它只关注按序接收的分组。
- 如果一个序号为
n
的分组被正确接收,并且它正是接收方所期望的(即n
等于expectedseqnum
),接收方会发送一个对n
的 ACK,并将其数据交付给上层。然后,expectedseqnum
递增。 - 如果收到一个失序(out-of-order)或损坏的分组,接收方会立即丢弃该分组,并重新发送一个对最近一次按序接收的分组的 ACK。
这种处理方式的优点是接收方不需要缓存任何失序的分组,实现起来更简单,唯一需要维护的信息就是下一个期望接收的分组序号。缺点是,如果一个分组丢失,它后面的所有分组即使正确到达,也会被接收方丢弃,直到丢失的分组被重传并按序到达。这可能导致不必要的重传,降低效率。
4.4 选择重传
选择重传(Selective Repeat, SR)协议旨在解决 GBN(回退 N 步)协议的性能问题。GBN 的“回退 N 步”重传机制效率低下,当单个分组丢失时,它会重传整个窗口内的大量分组,即使其中大部分已经正确到达接收方。SR 协议通过只重传那些被接收方明确标记为丢失或损坏的分组,避免了这种不必要的浪费。
(1)SR 协议的核心思想
SR 协议的核心在于“选择性”重传,这要求发送方和接收方都有更复杂的缓存和确认机制:
- 逐个确认:接收方会为每一个正确接收的分组发送一个单独的确认(ACK),不管该分组是否按序到达。
- 按需重传:发送方只重传那些未收到确认的分组。
- 窗口机制:与 GBN 类似,SR 也使用窗口长度 N 来限制发送方在流水线中未确认的分组数量。
(2)SR 发送方的工作机制
SR 发送方维护一个序号窗口,并针对以下三种事件采取不同行动:
- 从上层接收数据:发送方检查新分组的序号是否在当前窗口内。如果在,它会打包并发送该分组;如果不在,它会拒绝或缓存数据。
- 超时:SR 协议为每个已发送但未确认的分组都设置一个独立的定时器。一旦某个分组的定时器超时,发送方会只重传这一个分组,而不是整个窗口。
- 收到 ACK:当收到对某个分组的 ACK 时,如果该分组序号在窗口内,发送方会将其标记为已确认。如果这个 ACK 确认了窗口基序号(send_base)的分组,并且这个分组以及之前连续的分组都已确认,那么窗口将向前滑动到第一个未确认的分组。
(3)SR 接收方的工作机制
SR 接收方的行为比 GBN 复杂,因为它需要处理失序到达的分组:
- 正确接收窗口内的分组:如果收到的分组序号在接收方窗口内,接收方会向发送方发送一个对该分组的选择性 ACK。
- 如果分组是按序的:接收方会立即将该分组(及其之前已缓存的连续按序分组)交付给上层,然后窗口向前滑动。
- 如果是失序的:接收方会将其缓存起来,等待所有序号更小的分组都到达。
- 正确接收窗口之外的分组:如果收到的分组序号在
[rcv_base - N, rcv_base - 1]
范围内(即已经确认过的分组),接收方会重新发送一个 ACK。这是为了应对发送方窗口由于 ACK 丢失而未能向前滑动的情况,避免不必要的超时重传。 - 其他情况:接收方直接忽略该分组。
(4)SR 协议的挑战
SR 协议虽然更高效,但也有其固有的复杂性,特别是在处理有限序号范围和窗口同步问题时。
- 窗口同步问题:由于发送方和接收方的窗口状态可能不一致(例如,ACK 丢失),这可能导致发送方误以为分组已丢失并重传,而接收方却无法区分这是新分组还是旧分组的重传。
- 窗口大小限制:为了解决这种歧义,SR 协议的窗口长度必须小于或等于序号空间大小的一半。这确保了在任何时刻,旧的分组副本都不会与新的分组序号重叠,从而避免混淆。
五.面向连接的运输:TCP
5.1 TCP连接
TCP(传输控制协议)被称为面向连接的协议,因为它要求在两个应用进程开始发送数据之前,必须先通过一个“握手”过程建立起一条逻辑连接。
(1)连接的性质
- 逻辑连接:TCP 连接不是物理电路,该“连接”是一条逻辑连接。中间的网络元素(如路由器)对 TCP 连接是完全无知的,它们只处理 IP 数据报。
- 点对点:TCP 连接总是发生在单个发送方与单个接收方之间。它不支持多播(即一次发送给多个接收方)。
- 全双工:一旦建立连接,数据可以在两个方向上同时传输。
(2)三次握手
在发送数据前,客户端和服务器必须通过三次握手来建立连接:
- 客户端发送一个特殊的 TCP 报文段(不含应用数据)。
- 服务器响应一个特殊的 TCP 报文段(不含应用数据)。
- 客户端再响应一个特殊的报文段,这个报文段可以携带应用层数据。
总的来说,TCP 协议在完成三次握手后,连接就正式建立,双方都可以开始传输数据。但从技术层面讲,客户端可以在第三次握手时就捎带上第一段应用数据,这能稍微提高效率。
(3)数据传输与缓存
TCP 连接的组成包括 : 一台主机上的缓存、变量和与进程连接的套接字 ,以及另一台主机上的另一组缓存、变量和与进程连接的套接字 。
- 发送缓存:客户端进程将数据流传递给 TCP,TCP 将数据存入发送缓存。
- 报文段封装:TCP 从发送缓存中取出数据,并加上 TCP 首部,形成报文段。
- 最大报文段长度(MSS):TCP 从缓存中取出的数据量受限于 MSS。MSS 通常根据最初确定的由本地发送主机发送的最大链路层帧长度( 即所谓的最 大传输单元 (Maximum Transmission Unit, MTU)) 来设置。
- 接收缓存:接收方 TCP 收到报文段后,将其数据存入接收缓存。应用程序从这个缓存中读取数据流。
5.2 TCP报文段结构
TCP 报文段由一个首部字段和一个数据字段组成,其中数据字段承载应用数据。
(1)TCP 报文段首部结构
- 源端口号和目的端口号:用于多路复用和多路分解。
- 检验和:用于差错检查。
- 序号(Sequence Number):32 比特,用于可靠数据传输。
- 确认号(Acknowledgment Number):32 比特,用于可靠数据传输。
- 接收窗口(Receive Window):16 比特,用于流量控制,指示接收方还能接受多少字节的数据。
- 首部长度:4 比特,指示 了以32比特的字为单位的TCP 首部的长度(因为有选项字段)。
- 标志位(Flags):6 比特,
- 包括
ACK
(用于确认号字段是否有效),RST
、SYN
、FIN
(用于连接建立与拆除),CWR
和ECE
用于明确拥塞通知。 - 当
PSH
指示接收方是否应立即将数据交给上层 。URG
指示报文段里存在着被发送端的上层实体置为”紧急”的数据 。但指出PSH
和URG
以及紧急数据指针在实际中很少使用,所以主要的功能性标志位就是那 6 个。
- 包括
- 选项字段:可选和可变长度。
(2)序号和确认号
TCP 协议将数据视为一个无结构的、有序的字节流。
- 序号:
- 一个报文段的序号是该报文段中第一个字节的字节流编号。
- 例如,如果一个 50 万字节的文件被分割成 1000 字节的报文段,第一个报文段的序号是 0,第二个是 1000,以此类推。
- TCP 连接的初始序号是随机选择的,以避免与之前连接的报文段混淆。
- 确认号:
- 发送方发出的确认号是它期望从接收方收到的下一个字节的序号。
- TCP 提供累积确认。例如,如果主机 A 收到来自主机 B 的所有到第 535 个字节的数据,那么主机 A 发给主机 B 的报文段中的确认号将是 536,表示它已经确认了 535 之前的所有字节,现在期待从 536 字节开始的数据。
- 如果主机收到失序的报文段(即中间有数据缺失),它仍然会发送一个包含最早缺失字节序号的确认号。
捎带:确认信息可以被“捎带”在从接收方发往发送方的数据报文段中。这意味着一个报文段可以同时包含从一个方向传输的数据和对另一个方向传输的数据的确认。
5.3 往返时间的估计与超时
TCP 采用超时/重传机制来确保可靠的数据传输。为了有效管理这个机制,正确设置超时间隔(TimeoutInterval)至关重要,它必须大于报文段的往返时间(RTT)。
(1)估计往返时间(RTT)
TCP 不为每个报文段都测量 RTT,而是采用一种平滑的、加权平均的方法来估计 RTT:
- 样本 RTT (SampleRTT):这是从发送一个报文段到收到其确认之间的时间。为了避免因重传而造成的测量偏差,TCP 只为未重传的报文段计算
SampleRTT
。 - 估计 RTT (EstimatedRTT):
EstimatedRTT
是对SampleRTT
的加权平均值,它会随着新的测量值不断更新。- 计算公式:
EstimatedRTT = (1 - α) * EstimatedRTT + α * SampleRTT
- 推荐值:
α = 0.125
。 - 特点:这种方法称为指数加权移动平均(EWMA),它会赋予最近的
SampleRTT
更大的权重,使其更能反映当前的网络状况。
- 计算公式:
(2)估计 RTT 的偏差
为了衡量 SampleRTT
的波动程度,TCP 还引入了 DevRTT
(RTT 偏差)变量:
- 计算公式:
DevRTT = (1 - β) * DevRTT + β * |SampleRTT - EstimatedRTT|
- 推荐值:
β = 0.25
。 - 用途:
DevRTT
能够反映SampleRTT
相对于EstimatedRTT
的平均偏离程度,波动越大,DevRTT
值越高。
(3)设置超时间隔
超时间隔设为 EstimatedRTT加上一定余量。当sampleRTT 值波动较大时,这个余量应该大些;当波动较小时,这个余量应该小些。因此, DevRTT 值应该在这里发挥作用了。
TCP 的超时间隔是根据 EstimatedRTT
和 DevRTT
来动态调整的,以确保它既能应对网络波动,又不会因为设置过长而影响传输效率。
- 计算公式:
TimeoutInterval = EstimatedRTT + 4 * DevRTT
- 初始值:推荐的初始
TimeoutInterval
值为 1 秒。
5.4 可靠数据传输
TCP 在不可靠的 IP 服务之上,建立了一种可靠数据传输服务。它确保从接收方缓存中读出的数据流是无损、无冗余、无间隙且按序的。TCP 的可靠性主要依赖于超时/重传和冗余确认两种机制。
(1)基本的超时/重传机制
- 单一计时器:TCP 使用一个单一的定时器来管理所有已发送但未确认的报文段。这个定时器与最早发送但尚未被确认的报文段相关联。
- 发送方操作:
- 发送数据:当从应用程序接收数据时,TCP 将其封装成报文段,并启动定时器(如果尚未运行)。
- 处理超时:如果定时器超时,TCP 会重传最早未被确认的报文段,并重启定时器。
- 处理 ACK:当收到确认报文(ACK)时,如果确认号大于已发送但未确认的字节序号(
SendBase
),说明有新数据被确认。发送方会更新SendBase
,并根据是否有未确认的报文段来决定是否重启定时器。
(2)超时间隔加倍
为了应对网络拥塞,TCP 在发生超时重传时,会采用一种指数退避的策略:
- 超时加倍:每当定时器超时时,TCP 将下一次的超时间隔加倍,而不是使用之前计算的
TimeoutInterval
值。当收到新的 ACK 时,超时间隔会重新根据EstimatedRTT
和DevRTT
计算。 - 目的:这种机制是一种形式的拥塞控制。定时器过期很可能是由网络拥塞引起的,即太多的分组到达源与目的地之间路 径上的一台(或多台)路由器的队列中,造成分组丢失或长时间的排队时延 。在拥塞的时候,如果源持续重传分组,会使拥塞更加严重。相反, TCP 使用更文雅的方式 ,每个 发送方的重传都是经过越来越长的时间间隔后进行的 。
(3)快速重传
超时等待时间可能很长,导致传输延迟。为了更早地检测到丢包,TCP 引入了快速重传机制。
- 冗余 ACK:当接收方收到一个失序的报文段(即发现数据流中存在空缺)时,它不会发送否定确认,而是发送一个冗余 ACK,再次确认它所期望的下一个按序字节。
- 触发重传:如果 TCP 发送方连续收到三个对同一报文段的冗余 ACK,它会认为该报文段已丢失。
- 机制:发送方会立即执行快速重传,在定时器超时之前重传丢失的报文段,从而大大减少了等待时间。
这个机制的好处是,它能在超时之前发现丢包,从而更快地恢复数据传输,减少不必要的延迟。
(4) GBN vs. SR vs. TCP
- GBN(回退N步)协议:当发送方发现某个分组(或报文段)丢失时,它会重传该分组以及其后的所有分组,即使后面的分组已经被接收方收到了。这种方式简单,但效率较低。
- SR(选择重传)协议:当发送方发现某个分组丢失时,它只重传那个丢失的分组。接收方会缓存所有已收到的但失序的分组,等待缺失的分组到达,再一起向上交付。这种方式更复杂,但更高效。
- TCP 与 GBN 的相似之处:TCP 使用累积确认。它只会确认到目前为止所有按序收到的数据。例如,如果它收到了字节0-999,然后收到了1200-1499,但中间的1000-1199丢了,它只会给你一个确认号1000,表示它只收到了1000之前的。这一点和 GBN 很像。
- TCP 与 SR 的相似之处:许多 TCP 实现都会缓存失序的报文段(比如上面的1200-1499),而不是像 GBN 那样直接丢弃。当它收到缺失的报文段(1000-1199)后,可以马上把所有数据拼接好。
- 结论:它使用 GBN 的累积确认方式,但在处理丢包时,它又像 SR 一样只重传丢失的报文段(通过快速重传机制),并且会缓存已经收到的失序报文段。这使得 TCP 既能保持相对简单,又能高效地应对丢包情况。
5.5 流量控制
TCP 的流量控制是一种速度匹配服务,旨在防止发送方的数据发送速率超过接收方应用程序的处理速率,从而避免接收方的接收缓存溢出。
(1)流量控制的机制
TCP 依靠一个名为接收窗口(Receive Window,rwnd
)的变量来实现流量控制。 - 接收缓存:每条 TCP 连接在接收端都分配一个接收缓存(
RcvBuffer
),用于存放从网络接收到的数据。应用程序从这个缓存中读取数据。 rwnd
的计算:接收方持续跟踪其接收缓存中可用的空间,并用rwnd
变量表示。rwnd
的值等于RcvBuffer
减去已被接收但尚未被应用程序读取的数据量。- 公式:
rwnd = RcvBuffer - [LastByteRcvd - LastByteRead]
- 公式:
rwnd
的通告:接收方会将当前的rwnd
值放入它发送给发送方的 TCP 报文段的接收窗口字段中。- 发送方的限制:发送方会维护一个变量
LastByteAcked
(已被确认的最后一个字节序号)和LastByteSent
(已发送的最后一个字节序号)。发送方必须确保其未确认的数据量(LastByteSent - LastByteAcked
)不超过接收方通告的rwnd
值。
(2)处理“零窗口”问题
- 问题:如果接收方的应用程序读取数据很慢,导致其接收缓存被填满,
rwnd
值就会变为 0。当接收方将rwnd=0
通告给发送方后,如果它没有数据要发送,TCP 将不会向发送方发送新的报文段来更新rwnd
值,从而导致发送方被无限期地阻塞。 - 解决方案:为了解决这个问题,当发送方收到
rwnd=0
的通告后,它会继续发送只有一个字节数据的探测报文段。接收方收到这些探测报文段后,会发送一个确认,其中包含最新的rwnd
值。一旦rwnd
不为 0,发送方就可以恢复数据传输。
(3)流量控制与拥塞控制的区别
虽然流量控制和拥塞控制(在后续章节讨论)都旨在控制发送速率,但它们解决的问题不同:
- 流量控制:是点对点的,旨在匹配发送方与接收方应用程序的读写速度,防止接收缓存溢出。
- 拥塞控制:是全局的,旨在避免因网络中路由器拥塞而导致的丢包和性能下降。
5.6 TCP连接管理
(1)TCP 连接建立:三次握手
TCP 连接的建立需要三次握手来确保双方都准备好进行通信,其过程如下:
- SYN:客户端(Client)的 TCP 向服务器(Server)发送一个特殊的 SYN 报文段。这个报文段的
SYN
标志位被置为1,同时包含一个随机生成的初始序号(client_isn
)。 - SYN + ACK:服务器接收到 SYN 报文段后,为该连接分配资源,并向客户端发送一个 SYNACK 报文段。该报文段的
SYN
和ACK
标志位都置为1。其确认号被设置为client_isn + 1
,同时包含服务器自己随机生成的初始序号(server_isn
)。 - ACK:客户端收到 SYNACK 报文段后,会向服务器发送最后一个报文段。该报文段的
ACK
标志位被置为1,确认号设置为server_isn + 1
。由于连接已建立,该报文段的SYN
标志位被置为0,并且可以携带应用层数据。
完成这三步后,连接正式建立,双方可以开始全双工的数据传输。
(2)TCP 连接拆除:四次挥手
任何一方都可以发起关闭连接的请求。以客户端发起为例: - FIN:客户端的应用进程发出关闭命令,其 TCP 向服务器发送一个
FIN
标志位被置为1的报文段。 - ACK:服务器收到
FIN
报文段后,发送一个确认(ACK)报文段作为响应。此时,服务器到客户端方向的连接仍然可以发送数据。 - FIN:当服务器也准备好关闭连接时,它会发送自己的
FIN
报文段。 - ACK:客户端收到服务器的
FIN
报文段后,发送最后一个确认(ACK)报文段。随后,客户端进入 TIME_WAIT 状态等待一段时间,以确保服务器收到最后的确认,然后释放所有资源。
完成这四步后,连接正式关闭。
六.拥塞控制原理
该文本节选自一本关于计算机网络的书籍,旨在解释网络拥塞控制的原理。
6.1 拥塞原因和代价
网络拥塞是指当过多的发送方试图以过高的速率发送数据时,导致路由器缓存溢出,从而引起分组丢失的现象。拥塞的代价体现在以下几个方面:
- 排队时延增大: 当分组到达速率接近链路容量时,会在路由器中产生巨大的排队时延,影响数据传输效率。
- 分组丢失与重传: 路由器缓存有限,当缓存满时会丢弃新到的分组。为了保证数据可靠传输,发送方必须重传这些丢失的分组,增加了网络负担。
- 不必要的重传: 发送方可能会因时延过大而过早超时,重传尚未丢失的分组。这会浪费宝贵的网络带宽,因为路由器需要处理和转发不必要的重复数据。
- 浪费传输容量: 在多跳路径中,如果一个分组在下游路由器被丢弃,则上游路由器为转发该分组所做的所有工作和使用的传输容量都将被浪费。
6.2 拥塞控制方法
拥塞控制的目的是遏制发送方,使其在网络拥塞时降低发送速率。根据网络层是否提供显式帮助,拥塞控制方法可分为两类:
- 端到端拥塞控制: 网络层不提供任何显式支持,发送方需要通过观察网络行为(如分组丢失、时延增加)来推断拥塞情况。
- 优点: 无需网络层协议支持,实现简单。
- 缺点: 响应不够精确和及时。
- 应用: TCP 协议就是采用这种方法,通过超时或三次冗余确认来判断拥塞。
- 网络辅助的拥塞控制: 路由器会向发送方提供显式反馈信息,告知网络中的拥塞状态。
- 优点: 响应更快速、精确,能更有效地管理网络资源。
- 缺点: 需要网络层协议支持,实现更复杂。
- 应用: ATM 和 DECnet 等体系结构曾采用此方法。反馈方式有两种:
- 直接反馈: 路由器直接向发送方发送“阻塞分组”(choke packet)来通知拥塞。
- 间接反馈: 路由器在流向接收方的分组中标记拥塞信息,接收方收到后通知发送方。
七.TCP拥塞控制
TCP 拥塞控制是一种端到端的机制,TCP所采用的方法是让每一个发送方根据所感知到的网络拥塞程度来限制其能向连接发送流量的速率 。
(1) 拥塞窗口(cwnd
)
- 工作原理:TCP 发送方通过一个额外的变量拥塞窗口(
cwnd
)来限制其发送速率。发送方在任何时刻未被确认的数据量,都不能超过cwnd
和接收窗口(rwnd
)的较小值。通常,在不考虑接收方限制的情况下,未确认数据量由cwnd
限制。 - 速率调节:发送方的发送速率大致等于
cwnd / RTT
(往返时间)。因此,通过调整cwnd
的大小,TCP 就能控制其向网络中发送数据的速率。
(2) 拥塞的感知
TCP 通过两种事件来隐式地感知网络拥塞:
- 丢包事件:
- 超时:当一个报文段的定时器超时,发送方会认为该报文段已丢失,这通常是网络拥塞的信号。
- 三个冗余 ACK:当发送方收到三个对同一报文段的重复确认(冗余 ACK)时,它也认为后续报文段已丢失,这同样是拥塞的信号。
- 确认的到达:当新的确认报文段(ACK)到达时,这被视为一个积极的信号,表明网络正在成功地交付数据,没有拥塞。TCP 使用这种“自计时”机制来调整发送速率。
(3)TCP 拥塞控制算法
TCP 拥塞控制算法主要分为三个阶段:
- 慢启动(Slow Start)
- 何时发生:连接建立时或发生超时丢包后。
- 机制:
cwnd
初始设置为 1 个 MSS(最大报文段长度)。每当收到一个新确认,cwnd
就会指数级增长,通常每经过一个 RTT 就会翻倍。 - 何时结束:
- 当
cwnd
达到慢启动阈值(ssthresh
)时,进入拥塞避免阶段。 - 当发生超时丢包时,
cwnd
被重置为 1 MSS,并进入慢启动,同时ssthresh
被设置为当前cwnd
的一半。 - 当发生三个冗余 ACK 时,进入快速恢复阶段。
- 当
- 拥塞避免
- 何时发生:当
cwnd
达到或超过ssthresh
时。 - 机制:为了避免拥塞,
cwnd
增长速度放缓,变为线性增长。每收到一个新确认,cwnd
只增加少量字节,直到在一个 RTT 内cwnd
仅增加 1 个 MSS。 - 何时结束:
- 发生超时丢包时,
cwnd
重置为 1 MSS,进入慢启动。 - 发生三个冗余 ACK 时,
cwnd
减半,进入快速恢复。
- 发生超时丢包时,
- 何时发生:当
- 快速恢复
- 何时发生:当收到三个冗余 ACK 时。
- 机制:
cwnd
减半(更精确地说,是cwnd
设置为ssthresh
,然后加上 3 个 MSS),并进入拥塞避免阶段。与超时不同,它不从慢启动开始,而是直接从拥塞避免阶段继续。这是一种更温和的拥塞响应机制。
(4)整体行为:加性增、乘性减(AIMD)
综合来看,TCP 的拥塞控制可以概括为 AIMD 策略:
- 加性增(Additive-Increase):在拥塞避免阶段,TCP 线性地增加
cwnd
(每 RTT 增加 1 MSS)。 - 乘性减(Multiplicative-Decrease):当检测到丢包事件时,TCP 会将
cwnd
减半。
这种“锯齿状”行为使得 TCP 能够持续探测网络的可用带宽,既能充分利用带宽,又能及时响应拥塞。