# 运输层概述
# 进程间基于网络的通信
- 计算机网络中实际进行通信的真正实体,是位于通信两端主机中的进程。
- 如何为运行在不同主机上的应用进程提供直接的逻辑通信服务,就是运输层的主要任务。运输层协议又称为端到端协议。
- 因特网的运输层为应用层提供了两种不同的运输层协议,即面向连接的 TCP 和无连接的 UDP
# TCP/IP 运输层中的两个重要协议
TCP
- 传输控制协议(Transmission Control Protocol,TCP)为其上层提供的是面向连接的可靠的数据传输服务。
- 使用 TCP 通信的双方,在传送数据之前必须首先建立 TCP 连接(逻辑连接,而非物理连接)。数据传输结束后必须要释放 TCP 连接。
- TCP 为了实现可靠传输,就必须使用很多措施,例如 TCP 连接管理、确认机制、超时重传、流量控制以及拥塞控制等。
- TCP 的实现复杂,TCP 报文段的首部比较大,占用处理机资源比较多。
UDP
- 用户数据报协议(User Datagram Protocol,UDP)为其上层提供的是无连接的不可靠的数据传输服务。
- 使用 UDP 通信的双方,在传送数据之前不需要建立连接。
- UDP 不需要实现可靠传输,因此不需要使用实现可靠传输的各种机制。
- UDP 的实现简单,UDP 用户数据报的首部比较小。
因特网应用 | TCP/IP 应用层协议 | TCP/IP 运输层协议 |
---|---|---|
域名解析 | 域名系统 DNS | UDP |
文件传送 | 简单文件传送协议 TFTP | UDP |
路由选择 | 路由信息协议 RIP | UDP |
网络参数配置 | 动态主机配置协议 DHCP | UDP |
网络管理 | 简单网络管理协议 SNMP | UDP |
远程文件服务器 | 网络文件系统 NFS | UDP |
IP 电话 | 专用协议 | UDP |
流媒体通信 | 专用协议 | UDP |
IP 多播 | 网际组管理协议 IGMP | UDP |
电子邮件 | 简单邮件传送协议 SMTP | TCP |
远程终端接入 | 电传机网络 TELNET | TCP |
万维网 | 超文本传送协议 HTTP | TCP |
文件传送 | 文件传送协议 FTP | TCP |
# 运输层端口号
- 运行在计算机上的进程是使用进程标识符(Process Identification,PID)来标识的。
- 然而,因特网上的计算机并不是使用统一的操作系统,而不同操作系统(Windows、Linux、MacOS)又使用不同格式的进程标识符。
- 为了使运行不同操作系统的计算机的应用进程之间能够基于网络进行通信,就必须使用统一的方法对 TCP/IP 体系的应用进程进行标识。
- TCP/IP 体系结构的运输层使用端口号来标识和区分应用层的不同应用进程。端口号的长度为 16 比特,取值范围是 0~65535。
- 服务器端口号
- 熟知端口号 0~1023: 由 IANA 分配给 TCP/IP 体系结构应用层中最重要的一些应用协议
- 登记端口号 1024~49151: 为没有熟知端口号的应用程序使用。要使用这类端口号,必须在 IANA 进行登记,以防止重复。例如,Microsoft RDP 微软远程桌面应用程序使用的端口号是 3389。
- 客户端使用端口号:
- 短暂端口号 49152~65535: 仅在客户端使用,由客户进程在运行时动态选择,通信结束后会被系统收回,以便给其他客户进程使用
- 端口号只具有本地意义,即端口号只是为了标识本计算机网络协议栈应用层中的各应用进程。在因特网中,不同计算机中的相同端口号是没有关系的,即相互独立。另外,TCP 和 UDP 端口号之间也是没有关系的。
FTP | SMTP | DNS | DHCP | HTTP | BGP | |
---|---|---|---|---|---|---|
21/20 | 25 | 53 | 67/68 | 80 | 179 | 443 |
# 发送方的复用和接收方的分用
# UDP 和 TCP 的对比
# 无连接的 UDP 和面向连接的 TCP
- 用户数据报协议 UDP(User Datagram Protocol)
- 传输控制协议 TCP (Transmission Control)
# UDP 和 TCP 对单播、多播和广播的支持情况
- UDP 支持单播,多播,广播
- TCP 要先握手建立信道,仅支持单播
# UDP 和 TCP 对应用层报文的处理
- UDP 在接收到应用进程的报文后直接加装 UDP 首部,不拆分也不拼接
- TCP 将发送方发送的字节流编号并存在自己的应用缓存中,TCP 根据发送策略,从发送缓存中提取一定数量的字节构建 TCP 报文段发送出去。接收方取出数据载荷也放在自己的接收缓存中。同时将一部分字节向上发给应用进程
- UDP 是面向应用报文的
- TCP 是面向字节流的
# UDP 和 TCP 对数据传输可靠性的支持情况
- UDP 向上层提供无连接不可靠传输服务 (中途被丢弃什么也不做)(适用于 IP 电话、视频会议等实时应用)
- 即使网际层提供的是无连接不可靠的传输服务,TCP 在运输层依然能 TCP 向上层提供面向连接的可靠传输服务(适用于要求可靠传输的应用,例如文件传输), 无传输差错(误码、丢失、乱序和重复)
# UDP 首部和 TCP 首部的对比
用户数据报协议 UDP (User Datagram Protocol) |
传输控制协议 TCP (Transmission Control Protocol) |
---|---|
无连接 | 面向连接 |
支持 “一对一”、“一对多”、“多对一” 和 “多对多” 交互通信。 | 每一条 TCP 连接只能有两个端点 EP,只能是一对一通信。 |
面向应用报文 | 面向字节流 |
尽最大努力交付,即不可靠;不使用流量控制和拥塞控制。 | 可靠传输,使用流量控制和拥塞控制。 |
首部开销小,仅 8 字节。 | 首部最小 20 字节,最大 60 字节。 |
# 传输控制协议
# TCP 报文段的首部格式
- TCP 的全部功能需要依靠其首部中的各字段来实现
- 源端口和目的端口不再赘述
- 序号
- 确认号
- 确认标志位 ACK
- 数据偏移
- 占 4 比特,该字段的取值以 4 字节为单位。
- 指出 TCP 报文段的数据载荷部分的起始处距离 TCP 报文段的起始处有多远,这实际上指出了 TCP 报文段的首部长度
- 保留位占 6 比特,保留为以后使用。现在应置为 0
- 窗口
- 占 16 比特,该字段的取值以字节为单位
- 指出发送本报文段的一方的接收窗口的大小,即接收缓存的可用空间大小,这用来表征接收方的接收能力。
- 在计算机网络中,经常用接收方的接收能力的大小来控制发送方的数据发送量,这就是所谓的流量控制
- 检验和
- 占 16 比特
- 用来检查整个 TCP 报文段在传输过程中是否出现了误码。
- 与 UDP 类似,要在 TCP 首部前面加上伪首部,格式与 UDP 用户数据报的伪首部一样
- 同步标志位 SYN
- 用于 TCP “三报文握手” 建立连接。
- 当 SYN=1 且 ACK=0 时,表明这是一个 TCP 连接请求报文段。
- 对方若同意建立连接,则应在响应的 TCP 报文段的首部中使 SYN=1 且 ACK=1。
- 综上所述,SYN 为 1 的 TCP 报文段要么是一个连接请求报文段,要么是一个连接响应报文段
- 终止标志位 FIN
- 用于 TCP “四报文挥手” 释放连接。
- 当 FIN=1 时,表明此 TCP 报文段的发送方已经将全部数据发送完毕,现在要求释放 TCP 连接。
- 复位标志位 RST
- 用于复位 TCP 连接。
- 当 RST=1 时,表明 TCP 连接中出现严重差错,必须释放连接,然后再重新建立连接。
- RST 置 1 还用来拒绝一个非法的 TCP 报文段或拒绝打开一个 TCP 连接。
- 推送标志位 PSH
- 发送方 TCP 把 PSH 置 1,并立即创建一个 TCP 报文段发送出去,而不需要积累到足够多的数据再发送。
- 接收方 TCP 收到 PSH 为 1 的 TCP 报文段,就尽快地交付给应用进程,而不再等到接收到足够多的数据才向上交付
- 出于效率的考虑,TCP 的发送方可能会延迟发送数据,而 TCP 的接收方可能会延迟向应用进程交付数据。这样可以一次处理更多的数据。但是当两个应用进程进行交互式通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应。在这种情况下,应用进程可以通知 TCP 使用推送(PUSH)操作。
- 紧急标志位 URG
- 当 URG=1 时,紧急指针字段有效
- 当 URG=0 时,紧急指针字段无效
- 紧急指针
- 占 16 比特,以字节为单位,用来指明紧急数据的长度。
- 当发送方有紧急数据时,可将紧急数据 “插队” 到发送缓存的最前面,并立刻封装到一个 TCP 报文段中进行发送。紧急指针会指出本报文段数据载荷部分包含了多长的紧急数据,紧急数据之后是普通数据。
- 接收方收到紧急标志位为 1 的 TCP 报文段,会按照紧急指针字段的值从报文段数据载荷中取出紧急数据并直接上交应用进程,而不必在接收缓存中排队。
- 选项(长度可变,最大 40 字节)
- 最大报文段长度 MSS 选项:指出 TCP 报文段数据载荷部分的最大长度,而不是整个 TCP 报文段的长度。
- 窗口扩大选项:用来扩大窗口,提高吞吐率。
- 时间戳选项:
- 用于计算往返时间 RTT
- 用于处理序号超范围的情况,又称为防止序号绕回 PAWS。
- 选择确认选项:用来实现选择确认功能
- 填充
- 若选项字段的长度加上 20 字节固定首部的长度不能被 4 字节整除时,需要填充相应数量的比特 0,以确保首部长度能被 4 字节整除。
- 因为首部长度字段以 4 字节为单位,0101 代表 20 个字节
-
主机甲与主机乙之间已建立一个 TCP 连接,机甲向主机乙发送了两个连续的 TCP 段,分别包含 300 字节和 500 字节的有效载荷,第一个段的序号为 200,主机乙正确接收到两个段后,发送给主机甲的确认序列号是
第一段数据载荷开头 200, 结尾 499
第二段数据载荷开头 500, 结尾 999
则下一个确认号应该是 1000 -
主机甲与主机乙之间已建立一个 TCP 连接,双方持续有数据传输,且数据无差错与丢失。若甲收到 1 个来自乙的 TCP 段,该段的序号是 1913、确认序号为 2046、有效载荷为 100 字节,则甲立即发送给乙的 TCP 段的序号和确认序号分别是
-
主机甲与主机乙之间已建立一个 TCP 连接,主机甲向主机乙发送了 3 个连续的 TCP 段,分别包含 300 字节、400 字节和 500 字节的有效载荷,第 3 个段的序号为 900,若主机乙仅正确接收到第 1 和第 3 个段,则主机乙发送给主机甲的确认序号是
# TCP 的运输连接管理
- TCP 是面向连接的协议,它基于运输连接来传送 TCP 报文段。
- TCP 运输连接的建立和释放,是每一次面向连接的通信中必不可少的过程。
- TCP 运输连接有以下三个阶段:
- 通过 ==“三报文握手” 来建立 TCP 连接 ==。
- 基于已建立的 TCP 连接进行可靠的数据传输。
- 在数据传输结束后,还要通过 “四报文挥手” 来释放 TCP 连接。
# “三报文握手” 建立 TCP 连接
- “三报文握手” 建立 TCP 连接的目的在于解决以下三个主要问题:
- 使 TCP 双方能够确知对方的存在。
- 使 TCP 双方能够协商一些参数(例如最大报文段长度、最大窗口大小、时间戳选项等)。
- 使 TCP 双方能够对运输实体资源进行分配和初始化。运输实体资源包括缓存大小、各状态变量、连接表中的项目等。
- TCP 客户和服务器一开始都属于关闭状态
- TCP 控制器创建传输控制块 TCB
- TCP 连接表
- 指向发送和接收缓存的指针
- 指向重传队列的指针
- 当前的发送和接收序号…
- TCP 服务器进入监听状态,被动等待 TCP 客户的连接请求,称为被动打开连接
- TCP 客户进程也要首先创建传输控制块 TCB
- TCP 客户向 TCP 服务器发送链接请求报文段,进入同步已发送状态,SYN-SENT, 称为主动打开连接
- 连接请求报文段的首部标志位 SYN=1,seq=x, 作为 TCP 客户进程选择的初始序号
- TCP 规定同步标志位 SYN 被设置为 1 的报文段(例如 TCP 连接请求报文段和 TCP 连接请求确认报文段)不能携带数据,但要消耗掉一个序号。
- 按上述规定,TCP 连接请求报文段不能携带数据(即没有数据载荷),但是会消耗掉序号 x。
- 因此,TCP 客户进程下一次发送的 TCP 报文段的数据载荷的第一个字节的序号为 x+1。
- TCP 服务器发送 TCP 连接请求确认报文段进入同步已接收状态,SYN-REVD
- 连接请求确认报文段首部 SYN=1.ACK=1,seq=y,ack=x+1
- 连接请求确认报文段也不能携带数据,但也要消耗序号
- ack=x+1 是对初始序号 x 的确认
- TCP 客户发送针对 TCP 连接请求确认报文段的普通 TCP 确认报文段,并进入连接已建立状态,ESTABLISHED
- 确认标志位 ACK 的值被设置为 1,SYN=0, 表明这是一个普通的 TCP 确认报文段。
- 因为 TCP 客户进程之前发送的 TCP 连接请求报文段的序号为 x,该报文段虽然不能携带数据,但要消耗掉一个序号。因此 TCP 客户进程发送的第二个报文段的序号为 x+1。
- TCP 规定普通的 TCP 确认报文段可以携带数据,但如果不携带数据,则不消耗序号。
- 如果该报文段不携带数据,则 TCP 客户进程要发送的下一个数据报文段的序号仍为 x+1
- 确认号 ack 字段的值被设置为 y+1,这是对 TCP 服务器进程所选择的初始序号 y 的确认。
- TCP 服务器也进入连接已建立状态
-
主机甲向主机乙发送一个(SYN=1,seq=11220)的 TCP 段,期望与主机乙建立 TCP 连接,若主机乙接受该连接请求,则主机乙向主机甲发送的正确的 TCP 段可能是
-
若主机甲主动发起一个与主机乙的 TCP 连接,甲、乙选择的初始序列号分别为 2018 和 2046,则第三次握手 TCP 段的确认序列号是
采用 “三报文握手” 而不是 “两报文握手” 来建立 TCP 连接,是为了防止已失效的 TCP 连接请求报文段突然又传送到了 TCP 服务器进程,因而导致错误
# “四报文挥手” 释放 TCP 连接
- TCP 客户主动关闭, 发送 TCP 连接释放报文段并进入终止等待 1 状态
- TCP 连接释放报文段首部中的终止标志位 FIN 和确认标志位 ACK 的值都被设置为 1。表明这是一个 TCP 连接释放报文段,同时也对之前收到的 TCP 报文段进行确认。
- 序号 seq 字段的值设置为 u,它等于 TCP 客户进程之前已经传送过的数据的最后一个字节的序号加 1
- TCP 规定终止标志位 FIN 等于 1 的 TCP 报文段即使不携带数据,也要消耗掉一个序号。\
- 确认号 ack 字段的值设置为 v,它等于 TCP 客户进程之前已收到的数据的最后一个字节的序号加 1。
- TCP 服务器发送 TCP 普通确认报文段并进入关闭等待状态
- 确认标志位 ACK 的值被设置为 1,表明这是一个 TCP 普通确认报文段。
- 序号 seq 字段的值设置为 v,它等于 TCP 服务器进程之前已传送过的数据的最后一个字节的序号加 1。这也与之前收到的 TCP 连接释放报文段中的确认号 v 匹配。
- 确认号 ack 字段的值设置为 u+1,这是对 TCP 连接释放报文段的确认。
- 从 TCP 客户进程到 TCP 服务器进程这个方向的连接就释放了,此时的 TCP 连接属于半关闭状态;
- TCP 客户进程已经没有数据要发送了。但 TCP 服务器进程如果还有数据要发送,TCP 客户进程仍要接收,也就是从 TCP 服务器进程到 TCP 客户进程这个方向的连接并未关闭。
- 半关闭状态可能会持续一段时
- TCP 服务器发送 TCP 连接释放报文段并进入最后确认状态
- 序号 seq 字段的值假定被设置为 w,这是因为在半关闭状态下 TCP 服务器进程可能又发送了一些数据。
- 确认号 ack 字段的值被设置为 u+1,这是对之前收到的 TCP 连接释放报文段的重复确认。
- TCP 客户发送 TCP 普通确认报文段并进入时间等待状态
- 确认标志位 ACK 的值设置为 1,表明这是一个 TCP 普通确认报文段。
- 序号 seq 字段的值设置为 u+1,这是因为 TCP 客户进程之前发送的 TCP 连接释放报文段虽然不携带数据,但要消耗掉一个序号。
- 确认号 ack 字段的值设置为 w+1,这是对所收到的 TCP 连接释放报文段的确认
- TCP 服务器收到确认报文后进入关闭状态
- TCP 客户等待 2MSL 后进入关闭状态
- MSL 是最长报文段寿命(Maximum Segment Lifetime)的英文缩写词,[RFC793] 建议为 2 分钟。也就是说,TCP 客户进程进入时间等待(TIME-WAIT)状态后,还要经过 4 分钟才能进入关闭(CLOSED)状态。
- 这完全是从工程上来考虑的。对于现在的网络,MSL 取为 2 分钟可能太长了,因此 TCP 允许不同的实现可根据具体情况使用更小的 MSL 值。
- 二者进入关闭状态后,均各自撤销相应的传输控制块 TCB
- TCP 服务器在接收到客户发来的信息后,启动保活计时器,通常为 2 小时
- 计时器到时后,发送 TCP 探测报文段,之后每隔 75 秒发送一次
- 若一连发送 10 个探测报文段后仍无 TCP 客户进程的响应,TCP 服务器进程就认为 TCP 客户进程所在主机出了故障,于是就关闭这个连接。
# TCP 的流量控制
若 TCP 用户持续发送 TCP 报文段,而 TCP 服务器正忙,有可能导致 TCP 服务器接收缓存溢出造成数据丢失
# TCP 流量控制的基本概念
- TCP 为应用程序提供了流量控制(Flow Control)机制,以解决因发送方发送数据太快而导致接收方来不及接收,造成接收方的接收缓存溢出的问题。
- 流量控制的基本方法:接收方根据自己的接收能力(接收缓存的可用空间大小)控制发送方的发送速率。
# TCP 的流量控制方法
- 假设:
- 网络不会拥塞(不考虑 TCP 的拥塞控制)
- 在 A 和 B 建立 TCP 连接时,B 告诉 A:“我的接收窗口 rwnd=400”,因此 A 将自己的发送窗口 swnd 也设置为 400。
- 主机 A 收到确认报文后调整自己的发送窗口 [201~600], 即向前滑动两格,前面两格内容在发送缓存中删除
- 同时 B 对 A 发了 rwnd=300, 则主机 A 调整自己的发送窗口大小
- 继续发送后续内容
- 一段时间后主机 A 的 201…300 这段报文的重传计时器超时了,重新发送
- …
A 发送的零窗口探测报文段到达 B 时,如果 B 此时的接收窗口值仍然为 0,那么 B 根本就无法接受该报文段,又怎么会针对该报文段给 A 发回确认呢?
- 实际上 TCP 规定:即使接收窗口值为 0,也必须接受零窗口探测报文段、确认报文段以及携带有紧急数据的报文段
如果零窗口探测报文段丢失了,还会打破死锁的局面吗?
- 因为零窗口探测报文段也有重传计时器, 当重传计时器超时后,零窗口探测报文段会被重传
- 主机甲和主机乙之间建立了一个 TCP 连接,TCP 最大段长度为 1000 字节。若主机甲的当前拥塞窗口为 4000 字节,在主机甲向主机乙连续发送两个最大段后,成功收到主机乙发送的第一个段的确认段,确认段中通告的接收窗口大小为 2000 字节,则此时主机甲还可以向主机乙发送的最大字节数是
# TCP 的拥塞控制
拥塞
鼻塞
蛋挞
# 拥塞控制的基本概念
- 在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络性能就要变坏,这种情况就叫作拥塞(congestion)。
- 计算机网络中的链路容量(带宽)、交换节点中的缓存和处理机等都是网络的资源。
- 若出现拥塞而不进行控制,整个网络的吞吐量将随输入负荷的增大而下降。
流量控制与拥塞控制的区别
- 都是控制源点的发送速率
- 流量控制:
- 以接收方的接收能力控制发送方(源点)的发送速率;
- 只与特定的点对点通信的发送方和接收方之间的流量有关
- 拥塞控制:
- 源点根据各方面因素,按拥塞控制算法自行控制发送速率;
- 全局性问题,涉及网络中所有的主机、路由器等
# 拥塞控制的基本方法
衡量网络拥塞的指标有:
- 由于缓存溢出而丢弃的分组的百分比
- 路由器的平均队列长度
- 超时重传的分组数量
- 平均分组时延和分组时延的标准差
根据拥塞信息的反馈形式,可将闭环拥塞控制算法分为
- 显式反馈算法:从拥塞节点(即路由器)向源点提供关于网络中拥塞状态的显式反馈信息。
- 隐式反馈算法:源点自身通过对网络行为的观察(例如超时重传或往返时间 RTT)来推断网络是否发生了拥塞。TCP 采用的就是隐式反馈算法。
进行拥塞控制是需要付出代价的:
- 可能需要在节点之间交换信息和各种命令,以便选择拥塞控制的策略并实施控制,这样会产生额外开销。
- 可能需要预留一些资源用于特殊用户或特殊况,这样就降低了网络资源的共享程度
拥塞控制并不仅仅是运输层要考虑的问题。显式反馈算法就必须涉及网络层。虽然一些网络体系结构(如 ATM 网络)主要在网络层实现拥塞控制,但因特网主要利用隐式反馈在运输层实现拥塞控制
# TCP 的四种拥塞控制方法
包括:
- 慢开始(slow-start)
- 拥塞避免(congestion avoidance)
- 快重传(fast retransmit)
- 快恢复(fast recovery)
假定:
- 数据是单方向传送的,而另一个方向只传送确认。
- 接收方总是有足够大的接收缓存空间,因而发送方的发送窗口的大小仅由网络的拥塞程度来决定,也就是不考虑接收方对发送方的流量控制。
- 以 TCP 最大报文段 MSS(即 TCP 报文段的数据载荷部分)的个数作为讨论问题的单位,而不是以字节为单位(尽管 TCP 是面向字节流的)。
swnd=min(rwnd,cwnd)
门槛, 阈
慢开始算法和拥塞避免算法
- 慢开始(slow-start): 一开始 cwnd 设置较小,每次收到报文段确认后都指数增加 (1,2,4,8,16…) 直到大于等于 ssthresh 时更改策略
- 拥塞避免(congestion avoidance):
- 每隔传输轮次结束后线性 + 1;
- 出现丢失后触发超时重传,置 ssthresh 的值为发生拥塞时 cwnd 的一半;cwnd 从头慢开始
有时候只是出现误码而不是拥塞,重传计时器超时,误认为网络出现拥塞,将 cwnd 的值陡然降低为 1 并错误地启动慢开始算法,因而降低了传输效率
- 快重传(fast retransmit)
- 快恢复(fast recovery)
快重传算法和快恢复算法(改进 TCP 性能,1990 年 Reno 版本)
-
采用快重传算法可以让发送方尽早知道发生了个别 TCP 报文段的丢失。
-
“快重传” 是指使发送方尽快(尽早)进行重传,而不是等重传计时器超时再重传。
- 这就要求接收方不要等待自己发送数据时才进行捎带确认,而是要立即发送确认,即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认。
- 发送方一旦收到 3 个连续的重复确认,就将相应的报文段 (显然是没收到的报文) 立即重传,而不是等该报文段的重传计时器超时再重传。
-
对于个别丢失的报文段,发送方不会出现超时重传,也就不会误认为出现了拥塞而错误地把拥塞窗口 cwnd 的值减为 1。实践证明,使用快重传可以使整个网络的吞吐量提高约 20%。
-
与快重传算法配合使用的是快恢复算法,发送方一旦收到 3 个重复确认,就知道现在只是丢失了个别的报文段,于是不启动慢开始算法,而是执行快恢复算法。
- 发送方将慢开始门限 ssthresh 的值和拥塞窗口 cwnd 的值都调整为当前 cwnd 值的一半,并开始执行拥塞避免算法。
- 也有的快恢复实现是把快恢复开始时的 cwnd 值再增大一些,即 cwnd = 新 ssthresh+3。
- 既然发送方收到了 3 个重复的确认,就表明有 3 个数据报文段已经离开了网络。
- 这 3 个报文段不再消耗网络资源而是停留在接收方的接收缓存中。
- 可见现在网络中不是堆积了报文段而是减少了 3 个报文段,因此可以适当把 cwnd 值增大一些。
# TCP 拥塞控制与网际层拥塞控制的关系
-
路由器的输入缓存(可看作缓存队列,以下简称为队列)通常都按照 “先进先出 FIFO” 的规则来处理到达的 IP 数据报。由于队列长度总是有限的,因此当队列已满时,之后再到达的所有 IP 数据报都将被丢弃,这就叫作尾部丢弃策略
-
TCP 报文段的这些发送方产生超时重传,这将导致它们将拥塞窗口 cwnd 的值陡降为 1,因此送窗口 swnd 的值也降低为 1,并且进入 TCP 拥塞控制的慢开始阶段,称为全局同步。
-
全网的通信量骤降,而在网络恢复正常后,其通信量又突然增大很多。
-
为了避免网络中出现全局同步问题,在 1998 年提出了主动队列管理(Active Queue Management,AQM)。
- 所谓 “主动”,就是在路由器的队列长度达到某个阈值但还未满时就主动丢弃 IP 数据报,而不是要等到路由器的队列已满时才不得不丢弃后面到达的 IP 数据报,这样就太被动了。
- 应当在路由器队列长度达到某个值得警惕的数值时,也就是网络出现了某些拥塞征兆时,就主动丢弃到达的 IP 数据报来造成发送方的超时重传,进而降低发送方的发送速率,因而有可能减轻网络的拥塞程度,甚至不出现网络拥塞。
-
主动队列管理 AQM 可以有不同的实现方法,其中曾流行多年的就是随机早期检测(Random Early Detection,RED),也称为随机早期丢弃(Random Early Drop,RED 或 Random Early Discard,RED)。
- 路由器需要维护两个参数来实现 RED:队列长度最小门限和最大门限。当每一个 IP 数据报到达路由器时,RED 就按照规定的算法计算出当前的平均队列长度。
- 若平均队列长度小于最小门限,则把新到达的 IP 数据报存入队列进行排队。
- 若平均队列长度大于最大门限,则把新到达的 IP 数据报丢弃。
- 若平均队列长度在最小门限和最大门限之间,则按照某一丢弃概率 p 把新到达的 IP 数据报丢弃(这体现了丢弃 IP 数据报的随机性)
- 路由器需要维护两个参数来实现 RED:队列长度最小门限和最大门限。当每一个 IP 数据报到达路由器时,RED 就按照规定的算法计算出当前的平均队列长度。
因特网工程任务组 IETF 曾经推荐在因特网中的路由器使用 RED 机制 [RFC 2309],但多年的实践证明,RED 的使用效果并不理想。因此,在 2015 年公布的 [RFC 7567] 已经把 [RFC 2309] 列为 “陈旧”,并且不再推荐使用 RED。然而,对路由器进行主动队列管理 AQM 仍然是必要的。现在已经有几种不同的算法来代替旧的 RED,但都还在实验阶段。目前还没有一种算法能够成为 IETF 的标准,有兴趣的同学可以注意这方面的进展
# TCP 可靠传输的实现
注意
ackn 在选择重传协议与 TCP 协议中并不完全相同。
在选择重传协议中, ackn 表明序号到 n 为止的数据已正确接收,现在期望收到序号为 n+1 的数据。
在 TCP 协议中, ackn 表明序号到 n-1 为止的数据已正确接收,现在期望收到序号为 n 的数据。
对于 TCP 可靠传输的实现,还需要做以下补充说明:
- 虽然发送方的发送窗口是根据接收方的接收窗口设置的,但在同一时刻,发送方的发送窗口并不总是和接收方的接收窗口一样大,这是因为:
- 网络传送窗口值需要经历一定的时间滞后,并且这个时间还是不确定的。
- 发送方还可能根据网络当时的拥塞情况适当减小自己的发送窗口尺寸。
- 对于不按序到达的数据应如何处理,TCP 并无明确规定。
- 如果接收方把不按序到达的数据一律丢弃,那么接收窗口的管理将会比较简单,但这样做对网络资源的利用不利,因为发送方会重复传送较多的数据。
- TCP 通常对不按序到达的数据先临时存放在接收窗口中,等到字节流中所缺少的字节收到后,再按序交付上层的应用进程。
- TCP 要求接收方必须有累积确认(这一点与选择重传协议不同)和捎带确认机制。这样可以减小传输开销。接收方可以在合适的时候发送确认,也可以在自己有数据要发送时把确认信息顺便捎带上。
- 接收方不应过分推迟发送确认,否则会导致发送方不必要的超时重传,这反而浪费了网络资源。TCP 标准规定,确认推迟的时间不应超过 0.5 秒。若收到一连串具有最大长度的报文段,则必须每隔一个报文段就发送一个确认 [RFC 1122]。
- 捎带确认实际上并不经常发生,因为大多数应用程序很少同时在两个方向上发送数据。
- TCP 的通信是全双工通信。通信中的每一方都在发送和接收报文段。因此,每一方都有自己的发送窗口和接收窗口。在谈到这些窗口时,一定要弄清楚是哪一方的窗口。
# TCP 超时重传时间的选择
- TCP 超时重传时间 RTO 的选择时 TCP 最复杂的问题之一
- 超时重传时间 RTO 应略大于往返时间 RTT
- TCP 下层是复杂的因特网环境:
- 主机 A 所发送的报文段可能只经过一个高速率的局域网
- 也可能经过多个低速率的网络
- 并且每个 IP 数据报的转发路由还可能不同
- 不能直接使用略大于某次测量得到的往返时间 RTT 样本的值作为超时重传时间 RTO。
- 但是,可以利用每次测量得到的 RTT 样本计算加权平均往返时间 RTTs,这样可以得到比较平滑的往返时间。
# TCP 的选择确认
- 在之前介绍 TCP 的快重传和可靠传输时,TCP 接收方只能对按序收到的数据中的最高序号给出确认。当发送方超时重传时,接收方之前已收到的未按序到达的数据也会被重传
- TCP 可以使用选择确认 (Selective ACK,SACK)
- SACK 相关文档并没有指明发送方应当怎样响应 SACK。因此大多数的 TCP 实现还是重传所有未被确认的数据块