Computer Network Notes 3:Transport Layer
传输层服务
传输服务和协议
为运行在不同主机上的应用进程提供逻辑通信,即进程到进程的远程逻辑通信
传输协议运行在端系统
- 发送方:将应用层的报文分成报文段,然后传递给网络层
- 接收方:将报文段重组成报文,然后传递给应用层
有多个传输层协议可供选择
- Internet:TCP 和 UDP
传输层 vs 网络层
网络层服务:主机之间的逻辑通信
传输层服务:进程间的逻辑通信
- 依赖于网络层的服务:延时、带宽 (不可加强)
- 加强网络层的服务:弥补可靠性,减少数据丢失、顺序混乱 (不可靠 -> 可靠);加密 (安全);复用/解复用
Internet 传输层协议
可靠地、保序的传输:TCP (字节流)
- 多路复用、解复用
- 拥塞控制
- 流量控制
- 建立连接
不可靠、不保序的传输:UDP (数据报)
- 多路复用、解复用
- 没有为尽力而为的 IP 服务添加更多的其它额外服务
都不提供的服务:延时保证、带宽保证
多路复用和解复用
基本概念
在发送方主机多路复用:从多个套接字接受来自多个进程的报文,根据套接字对应的 IP 地址和端口号等信息对报文段用头部加以封装,该头部信息用于以后的解复用
在接收方主机多路解复用:根据报文段的头部信息种的 IP 地址和端口号将接收到的报文段发给正确的套接字和对应的应用进程
多路解复用工作原理
解复用作用:TCP 或者 UDP 实体采用哪些信息,将报文段的数据部分交给正确的 socket,从而交给正确的进程
主机收到 IP 数据报
- 每个数据包有源 IP 地址和目标地址
- 每个数据报承载一个传输层报文段
- 每个报文段有一个源端口号和目标端口号 (特定应用有著名的端口号)
主机联合使用 IP 地址和端口号将报文段发送给合适的套接字
无连接 (UDP) 多路解复用
创建套接字:
- 服务器端
1
2
3serverSocket = socket(PF_INET, SOCK_DGRAM, 0);
bind(serverSocket, &sad, sizeof(sad));
// serverSocket 和 Sad指定的端口号捆绑 (UDP 和 TCP 不同) - 客户端
1
2
3ClientSocket = socket(PF_INET, SOCK_DGRAM,0);
// 没有Bind、ClientSocket 和 OS 为之分配的某个端口号捆绑
// 客户端使用什么端口号无所谓,客户端主动找服务器
在接收端,UDP 套接字用二元组标识 (目标 IP 地址、目标端口号)
当主机收到 UDP 报文段
- 检查报文段的目标端口号
- 用该端口号将报文段定位给套接字
如果两个不同源 IP 地址/源端口号的数据报,但是有相同的目标 IP 地址和端口号,则被定位到相同的套接字
- 创建拥有本地端口号的套接字
1
DatagramSocket mySocket1 = new DatagramSocket(12534);
- 当创建 UDP 段采用端口号,可以指定:目标 IP 地址、目标端口号
无连接传输:UDP
UDP:User Datagram Protocol [RFC 768]
“no frills”, “bare bones” Internet 传输协议
“尽力而为”的服务,报文可能丢失、送到应用程序的报文段乱序
无连接
- UDP 发送端和接收端之间没有握手
- 每个 UDP 报文段都被独立地处理
UDP 被用于
- 流媒体:丢失不敏感,速率敏感、应用可控制传输速率
- DNS
- SNMP
在 UDP 上实现可靠传输:
- 在应用层增加可靠性
- 应用特定的差错恢复
为什么要有 UDP
不建立连接(会增加延时)
简单:在发送端和接收端没有连接状态
报文段的头部很小 (开销小)
无拥塞控制和流量控制,UDP 可以尽可能快的发送报文段:应用 -> 传输的速率 = 主机 -> 网络的速率
UDP 校验和 (check sum)
目标:检测在被传输报文段种的差错,如比特反转
发送方:
- 将报文段的内容视为 16 比特的整数
- 校验和:报文段的加法和 (1 的补运算)
- 发送方将校验和放在 UDP 的校验和字段
接收方:
- 计算接收到的报文段的校验和
- 检查计算处的校验和与校验和字段的内容是否相等
- 不相等 —— 检测到差错
- 相等 —— 没有检测到差错,但也许还是有差错 (残存错误)
Internet 校验和例子:进位回滚
当数字相加时,在最高位的进位要回卷,再加到结果上
目标端:校验范围 + 校验和 = 1111111111111111 通过校验,否则没有通过校验
求和时,必须将进位回卷到结果上
可靠数据传输的原理
可靠数据传输 (RDT)
RDT 在应用层、传输层和数据链路层都很重要
信道的不考考特点决定了可靠数据传输协议的复杂性
可靠数据传输:问题描述
渐增式地开发可靠数据传输协议 (RDT) 的发送方和接收方
只考虑单项数据传输,但控制信息是双向流动的
双向的数据传输问题实际上是 2 个单项数据传输问题的综合
使用有限状态机 (FSM) 来描述发送方和接收方
状态:在该状态时,下一个状态只由下一个事件唯一决定
可靠数据传输协议:停止-等待
RDT 1.0:在可靠信道上的可靠数据传输
下层的信道是完全可靠的
- 没有比特出错
- 没有分组丢失
发送方和接收方的 FSM
- 发送方将数据发送到下层信道
- 接收方从下层信道接收数据
RDT 2.0:具有比特差错的信道
下层信道可能会出错:将分组中的比特翻转
- 用校验和来检测比特差错
问题:怎样从差错中回复
- 确认 (ACK):接收方显示地告诉发送方分组已被正确接收
- 否定确认 (NAK):接收方显示地告诉发送方分组发生了差错;发送方收到 NAK 后,重传分组
RDT 2.0 的新机制:采用差错控制编码进行差错检测
- 发送方差错控制编码、缓存
- 接收方使用编码检错
- 接收方的反馈:控制报文 (ACK, NAK);接收方 -> 发送方
- 发送方收到反馈相应的动作
缺陷 (-> RDT 2.1)
如果 ACK/NAK 出错
- 发送方不知道接收方发生了什么事情
- 发送方重传,可能重复;不重传,可能死锁 (或出错)
- 需要引入新的机制:序号 (sequence number)
处理重复
- 发送方在每个分组中加入序号
- 如果 ACK/NAK 出错,发送方重传当前分组
- 接收方丢弃 (不发给上层) 重复分组
- 停等协议:发送方发送一个分组,然后等待接收方的应答
发送方:
- 在分组中加入序列号
- 两个序列号 (0, 1)就足够:一次只发送一个未经确认的分组
- 必须检测 ACK/NAK 是否出错 (需要 EDC)
- 状态数变成了两倍:必须记住当前分组的序列号是 0 还是 1
接收方:
- 必须检测接收到的分组是否是重复的:状态会指示希望接收到的分组的序号为 0 还是 1
- 接收方并不知道发送方是否正确收到了 ACK/NAK
- 发送方不对收到的 ACK/NAK 给确认,没有安排确认的确认
- 接收方发送 ACK,如果后面接收方收到的是老分组 P0,则 ACK 错误;收到下一个分组 P1,则 ACK 正确
RDT 2.2:无 NAK 的协议
功能同 RDT 2.1,但只使用 ACK (ACK 要编号)
接收方对最后正确接收的分组发 ACK,以替代 NAK:接收方必须显示地包含被正确接收分组的序号
当收到重复的 ACK (如再次收到 ACK0) 时,发送方与收到 NAK 采取相同的动作:重传当前分组
为后面的一次发送多个数据单位做准备
- 一次能够发送多个
- 每一个的应答都有 ACK/NAK 麻烦
- 使用对前一个数据单位的 ACK,代替本数据单位的 NAK
- 确认信息减少一半,协议处理简单
达成不要 NAK 的目标
RDT 3.0:具有比特差错和分组丢失的信道
新的假设:下层信道可能会丢失分组 (数据或 ACK)
- 会死锁
- 机制还不够处理这种状况:检验和、序列号、ACK、重传
方法:发送方等待 ACK 一段合理的时间
- 发送端超时重传:如果到时没有收到 ACK -> 重传
- 问题:如果分组 (或 ACK) 只是被延迟了
- 重传会导致数据重复,但利用序列号可以处理这个问题
- 接收方必须指明被正确接收的序列号
- 需要一个倒数定时器
过早超时 (延迟的 ACK) 也能够正常工作,但是效率较低,一般的分组和确认是重复的
设置一个合理的超时时间比较重要
性能:
- RDT 3.0 可以工作,但链路容量比较大的情况下,性能很差
- 链路容量比较大,一次发一个 PDU 不能充分利用链路的传输能力
- 瓶颈在于网络协议限制了物理资源的利用
可靠数据传输协议:流水线
流水线 (pipeline) 协议
流水线:允许发送方在未得到对方确认的情况下,一次发送多个分组
- 必须增加序号的范围:用多个 bit 表示分组的序号
- 在发送方/接收方要有缓冲区
- 发送方缓冲:未得到确认,可能需要重传
- 接收方缓存:上层用户去用数据的速率 ≠ 接收到的数据速率;接收到的数据可能乱序,排序交付 (可靠)
- 两种通用的流水线协议:回退 N 步 (GBN) 和选择重传 (SR)
通用:滑动窗口 (slide window) 协议
发送缓冲区
- 形式:内存中的一个区域,落入缓冲区的分组可以发送
- 功能:用于存放已发送,但是没有得到确认的分组
- 必要性:需要重发时可用
发送缓冲区的大小:一次最多可以发送多少个未经确认的分组
- 停止等待协议 = 1
- 流水线协议 > 1;合理的值,不能很大,链路的利用率不能超过 100 %
发送缓冲区中的分组
- 未发送的:落入发送缓冲区中的分组,可以连续发送出去
- 已经发送出去的、等待对方确认的分组:发送缓冲区的分组只有得到确认才能删除
发送窗口滑动过程 - 相对表示方法
- 采用相对移动方式表示,分组不动
- 可缓冲范围移动,代表一段可以发送的权力
滑动窗口协议 - 发送窗口
- 发送窗口
- 发送缓冲区内容的一个范围
- 那些已发送但是未经确认分组的序号构成的空间
- 发送窗口的最大值 ≤ 发送缓冲区的值
- 一开始:没有发送任何一个分组
- 后沿 = 前沿
- 之间为发送窗口的尺寸 = 0
- 每发送一个分组,前沿移动一个单位
- 发送窗口前沿移动的极限:不能超过发送缓冲区
- 发送窗口后沿移动
- 条件:收到老分组的确认
- 结果:发送缓冲区罩住新的分组,来了分组可以发送
- 移动的极限:不能超过前沿,即后沿贴到前沿
滑动窗口协议 - 接收窗口
- 接收窗口 (receiving window) = 接收缓冲区
- 接收窗口用于控制那些分组可以接收
- 只有收到的分组序号落入接收窗口内才允许接收
- 若序号再接收窗口之外,则丢弃
- 接收窗口尺寸
- 接收窗口尺寸 Wr = 1,则只能顺序接收
- 接收窗口尺寸 Wr > 1,则可以乱序接收,但提交给上层的分组要按序
- 接收窗口的滑动
- 低序号分组的到来,接收窗口移动
- 高序号分组乱序到,缓存但不交付 (因为要实现 RDT,不允许失序),不滑动
- 接收窗口的发送确认
- 接收窗口尺寸 = 1:发送连续收到的最大的分组确认 (累计确认)
- 接收窗口尺寸 > 1:收到分组,发送那个分组的确认 (非累计确认/独立确认)
正常情况下的 2 个窗口互动
- 发送窗口
- 有新的分组落入发送缓冲区范围,发送 -> 前沿滑动
- 来了老的低序号分组的确认 -> 后沿向前滑动 -> 新的分组可以落入发送缓冲区的范围
- 接收窗口
- 收到分组,落入到接收窗口范围内,接收
- 是低序号,发送确认给对方
异常情况下 GBN 与 SR 协议中的窗口互动
异常情况下 GBN 的 2 窗口互动
- 发送窗口
- 新分组落入发送缓冲区范围,发送 -> 前沿滑动
- 超时重发机制让发送端将发送窗口中的所有分组发送出去
- 来了老分组的重复确认 -> 后沿不向前滑动 -> 新的分组无法落入发送缓冲区的范围 (如果此时发送缓冲区有新的分组可以发送)
- 接收窗口
- 收到乱序分组,没有落入到接收窗口范围内,抛弃
- (重复) 发送老分组的确认,累计确认
异常情况下 SR 的 2 窗口互动
- 发送窗口
- 新分组落入发送缓冲区范围,发送 -> 前沿滑动
- 超时重发机制让发送端将超时的分组重新发送出去
- 来了乱序分组的确认 -> 后沿不向前滑动 -> 新的分组无法落入发送缓冲区的范围 (如果此时发送缓冲区有新的分组可以发送)
- 接收窗口
- 收到乱序分组,落入到接收窗口范围内,接收
- 发送该分组的确认,单独确认
每发送一个分组,就要设定一个超时定时器,接收到分组确认时取消定时器
GBN 协议和 SR 协议的相同之处
- 发送窗口 > 1
- 一次可发送多个未经确认的分组
GBN 协议和 SR 协议的不同之处 (主要由于接收窗口大小不同)
- GBN:接收窗口尺寸 = 1
- 接收端:只能顺序接收
- 发送端:从表现来看,一旦一个分组没有发送成功,就要退回重发 (如 0,1,2,3,4 中 1 未成功,234 都发送出去,要返回 1 再发送:GB1)
- SR:接收窗口尺寸 > 1
- 接收端:可以乱序接收
- 发送端:发送0,1,2,3,4 中 1 未成功,234 都发送出去,无需重发,选择性发送 1
小结
GO-back-N
- 发送端最多在流水线中有 N 个未确认的分组
- 接收端只是发送累计型确认 (cumulative ack):接收端如果发现 gap,不确认信道来的分组
- 发送端拥有对最老的未确认分组的定时器
- 秩序设置一个定时器
- 当定时器到时时,重传所有未确认分组
GBN:发送方扩展的 FSM
GBN:接收方扩展的 FSM
- 只发送 ACK:对顺序接收的最高序号的分组
- 可能会产生重复的 ACK
- 只需记住 expectedseqnum;接收窗口 = 1;只一个变量就可以表示接收窗口
- 对乱序的分组
- 丢弃 (不缓存) -> 在接收方不缓存
- 对顺序接收的最高序号的分组进行确认 - 累计确认
Selective Repeat
- 发送端最多在流水线中有 N 个未确认的分组
- 接收方对每个到来的分组单独确认 ACKn (individual ack):非累计确认
- 接收窗口 > 1,可以缓存乱序的分组
- 最终将分组按顺序交付给上层
- 发送方为每个未确认的分组保持一个定时器:当超时定时器到时时,只重发到时未确认分组
- 发送窗口的最大值 (发送缓冲区) 限制发送未确认分组的个数
对比 GBN 和 SR
适用范围:
- 出错率低:比较适合 GBN,出错非常罕见,没有必要用复杂的 SR,为罕见的事件做日常准备和复杂处理
- 链路容量大 (延迟大、带宽大):适合 SR 而不是 GBN,否则一点出错代价太大
面向连接的传输:TCP
TCP 概述
点对点:一个发送方,一个接收方
可靠的、按顺序的字节流:没有报文边界
管道化 **(流水线)**:TCP 拥塞控制和流量控制设置窗口大小
发送和接受缓存
全双工数据:在同一连接中数据流双向流动;MSS:最大报文段
面向连接:在数据交换之前,通过握手 (交换控制报文) 初始化发送方、接收方的状态变量
有流量控制:发送方不会淹没接收方
TCP 序号、确认号
序号:报文段首字节在字节流的编号
确认号:期望从零乙方收到的下一个字节的序号;累计确认
Q:接收方如何处理乱序的报文段 - 没有规定
TCP 往返延时 (RTT) 和超时
怎样设置 TCP 超时
比 RTT 要长,但 RTT 是变化的
太短:太早超时,不必要的重传
太长:对报文段丢失反应太慢,消极
怎样估计 RTT?
sampleRTT:测量从报文段发出到收到确认的时间
- 如果又重传,忽略此次测量
- 定期测量
- sampleRTT 会变化,因此估计的 RTT 应该比较平滑
- 对几个最近的测量值求平均,而不是仅用当前的 sampleRTT
设置超时
EstimtedRTT + 安全便捷时间:
- EstimatedRTT 变化大 (方差大) -> 较大的安全边界时间
SampleRTT 会偏离 EstimatedRTT 多远:
- DevRTT = (1-β) * DevRTT + β * |SampleRTT - EstimatedRTT|
- 推荐值:β = 0.25
超时时间间隔设置为:
- TimeoutInterval = EstimatedRTT + 4 * DevRTT
TCP:可靠数据传输
TCP 在 IP 不可靠服务的基础上建立了 RDT
- 管道化 (pipeline) 的报文段:GBN or SR
- 累计确认 (像 GBN)
- 单个重传定时器 (像 GBN)
- 是否可以接受乱序报文没有规范
通过以下事件触发重传
- 超时:只重发那个最早的未确认段 (SR)
- 重复的确认:收到了 ACK50 之后又收到 3 个 ACK50
简化的 TCP 发送方
- 忽略重复的确认
- 忽略流量控制和拥塞控制
TCP 发送方事件
从应用层接收数据:
- 用 nextseq 创建报文段
- 序号 nextseq 为报文段首字节的字节流编号
- 如果还没有运行,启动定时器
- 定时器与最早未确认的报文段关联
- 过期间隔:TimeOutInterval
超时:
- 重传后沿最老的报文段
- 重新启动定时器
收到确认:
- 如果是对尚未确认的报文段确认
- 更新已被确认的报文序号
- 如果当前还有违背确认的报文段,重新启动定时器
产生 TCP ACK 的建议
快速重传
- 超时周期往往太长:在重传丢失报文段之前的延时太长
- 通过重复的 ACK 来检测报文段丢失
- 发送方通常连续发送大量报文段
- 如果报文段丢失,通常会引起多个重复的 ACK
- 如果发送方收到统一数据的 3 个冗余 ACK,重传最小序号的段
- 快速重传:在定时器过时之前重发报文段
- 它假设跟在呗确认的数据后面的数据丢失了
- 第一个 ACK 是正常的
- 收到第二个该段的 ACK,表示接收方到收到一个该段后的乱序段
- 收到第 3、4 个该段的 ACK,表示接收方收到该段之后的 2 个、3 个乱序段,可能性非常大段丢失了
TCP 流量控制
缓冲区 TCP 往里面写,app 从当中读取
流量控制:接收方控制发送方,不让发送方发送太多、太快以至于让接收方的缓冲区溢出
接收方在其向发送方的 TCP 段头部的 rwnd 字段 “通告” 其空闲 brffer 大小
- RcvBuffer 大小通过 socket 选项设置 (典型默认大小为 4096 字节)
- 很多操作系统自动调整 RcvBuffer
发送方限制未确认 (in-flight) 字节的个数 ≤ 接收方发送过来的 rwnd 值
保证接收方不会被淹没
TCP 连接建立
在正式交换数据之前,发送方和接收方握手建立通信关系:
- 同意建立连接 (每一方抖直到对方愿意建立连接)
- 同意连接参数
同意建立连接
Q:在网格中,2 次握手建立连接总是可行吗?
- 变化的延迟 (连接请求的段没有丢,但可能超时)
- 由于丢失造成的重传 (eg. req_conn(x))
- 报文乱序
- 互相看不到对方
解决方案:变化的初始序号 + 双方确认对方的序号 (3 次握手)
关闭连接
客户端、服务器分别关闭自己这一侧的连接
- 发送 FIN bit = 1 的 TCP 段
一旦接收到 FIN,用 ACK 回应
- 接到 FIN 段,ACK 可以和它自己发出的 FIN 段一起发送
可以处理同时的 FIN 交换
拥塞控制原理
拥塞
非正式的定义:太多数据需要网络传输,超过了网络的处理能力
与流量控制不同
拥塞的表现:
- 分组丢失 (路由器缓冲区溢出)
- 分组经历比较长的延迟 (在路由器的队列中排队)
拥塞的原因/代价:场景 1
拥塞的原因/代价:场景 2
现实情况:重复
- 分组可能丢失,由于缓冲器满而被丢弃
- 发送端最终超时,发送第二个拷贝,两个分组都被传到
拥塞代价:
- 为了达到一个有效输出,网络需要做更多的工作 (重传)
- 没有必要的重传,链路中包括了多个分组的拷贝:是那些没有丢失,经历的时间比较长 (拥塞状态) 但超时的分组;降低了的 “goodput”
拥塞的原因/代价:场景 3
拥塞代价:当分组丢失时,任何 “关于这个分组的上游传输能力” 都被浪费
拥塞控制方法
网络辅助的拥塞控制
路由器提供给端系统以反馈信息
- 单个 bit 置位,显示有拥塞 (SNA,DECbit,TCP/IP ECN,ATM)
- 显式提供发送端可以采用的速率
端到端拥塞控制
没有来自网络的显示反馈
端系统根据延迟和丢失事件推断是否有拥塞
TCP 采用的方法
ATM ABR 拥塞控制
ABR:available bit rate
- 弹性服务
- 如果发送端的路径 “轻载”:发送方使用可用带宽
- 如果发送方的路径用色了,发送方限制其发送的速度到一个最小保障速率上
RM (资源管理) 信元
- 有发送端发送,在数据心愿中间隔插入
- RM 信元中的比特被交换机设置 (网络辅助)
- NI bit:no increase in rate (轻微拥塞)速率不要增加了
- CI bit:congestion indication 拥塞指示
- 发送端发送的 RM 信元被接收端返回,接收端不做任何改变
在 RM 信元中的 2 个字节 ER (explicit rate) 字段
- 拥塞的交换机可能会降低信元中 ER 的值
- 发送端发送速度因此是最低的可支持速率
数据信元中的 EFCI bit:备用色的交换机设置为 1
- 如果在管理信元 RM 前面的数据信元 EFCI 被设置成了 1,接收端在返回的 RM 信元中设置 CI bit
TCP 拥塞控制
机制
端到端的拥塞控制机制
路由器不向主机有关拥塞反馈信息
- 路由器的负担较轻
- 符合网络核心简单的 TCP/IP 架构远离
端系统根据自身的到的信息,判断是否发生拥塞,从而采取动作
拥塞控制的几个问题
如何检测拥塞
- 轻微拥塞
- 拥塞
控制策略
- 在拥塞发生时如何动作降低速率:轻微拥塞和拥塞分别如何降低
- 在拥塞缓解时如何动作增加速率
拥塞感知
发送端如何探测到拥塞
某个段超时 (丢失事件):拥塞
- 超时时间到,某个段的确认没有来
- 原因 1:网络拥塞 (某个路由器缓冲区没空间了,被丢弃),概率大
- 原因 2:出错被丢弃 (各级错误,没有通过校验,被丢弃),概率小
- 一旦超时,就认为拥塞会有一定误判,但总体控制方向是对的
有关某个段的 3 次重复 ACK:轻微拥塞
- 段的第 1 个 ACK,正常,确认绿段,期待红段
- 段的第 2 个重复 ACK,意味着红段的后一段收到了,蓝段乱序到达
- 段的第 2、3、4 个 ACK 重复,意味着红段的后第 2、3、4 个段收到了,橙段乱序到达,同时红段丢失的可能性很大 (后面 3 个段都到了,红段还没到)
- 网络这时还能够进行一定程度的传输,拥塞但情况比第一种好
速率控制方法
如何控制发送端发送的速率
维持一个拥塞窗口的值:CongWin
发送端限制已发送但是未确认的数据量 (的上限)
- LastByteSent-LastByteAcked ≤ CongWin
从而粗略地控制发送方往网络中注入的速率
CongWin 是动态的,是感知到的网络拥塞程度的函数
- 超时或者 3 个重复 ACK,CongWin:
- 超时时:CongWin 降为 1 MSS,进入 SS 阶段然后再倍增到 CongWin / 2 (每个 RTT),从而进入 CA 阶段
- 3 个重复 ACK:CongWin 降为 CongWin / 2,CA 阶段
- 否则 (正常收到 ACK,没有发送以上情况):CongWin 跃跃欲试
- SS 阶段:加倍增加 (每个 RTT)
- CA 阶段:线性增加 (每个 RTT)
TCP 拥塞控制和流量控制的联合动作
联合控制方法:
- 发送段控制发送但是未确认的量同时也不能够超过接收窗口,满足流量控制要求
- SendWin = min{CongWin, RecvWin}
- 同时满足拥塞控制和流量控制要求
TCP 拥塞控制:策略概述
拥塞控制策略:
- 慢启动
- AIMD:线性增、乘性减少
- 超时时间后的保守策略
TCP 慢启动
当连接开始时,指数性增加 (每个 RTT) 发送速率直到发生丢失事件
- 每一个 RTT,CongWin 加倍
- 每收到一个 ACK 时,CongWin 加 1
- 慢启动阶段:只要不超时或 3 个重复 ACK,一个 RTT,CongWin 加倍
总结:初始速率很慢,但加速确是指数性的
- 指数增加,SS 时间很短,长期来看可以忽略
AIMD
乘性减:丢失事件后将 CongWin 降为 1,将 CongWin / 2 作为阈值,进入到慢启动阶段 (倍增直到 CongWin / 2)
加性增:当 CongWin > 阈值时,一个 RTT 如没有发生丢失事件,将 CongWin 加 1 MSS (探测)
当收到 3 个重复的 ACKs
- CongWin 减半
- 窗口 (缓冲区大小) 之后线性增长
当超时事件发生时
- CongWin 被设置成 1 MSS,进入 SS 阶段
- 之后窗口指数增长
- 增长到一个阈值 (上次发生拥塞的窗口的一半) 时,再线性增加
思路:
- 3 个重复的 ACK 表示网络还有一定的段传输能力
- 超时之前的 3 个重复的 ACK 表示 “警报”
改进
- 什么时候应该将指数性增长变成线性
- 在超时之前,当 CongWin 变成上次超时时的窗口的一半
实现
- 变量:Threshold
- 出现丢失,Threshold 设置成 CongWin 的 1/2
总结
当 CongWin < Threshold,发送端处于慢启动阶段 (slow-start),窗口指数型增长
当 CongWin > Threshold,发送端处于拥塞避免阶段 (congestion-avoidance),窗口线性增长
当收到三个重复的 ACKs (triple duplicate ACK),Threshold 设置成 CongWin / 2,CongWin = Threshold + 3
当超时事件发生时 (timeout),Threshold = CongWin / 2,CongWin = 1 MSS,进入 SS 阶段
TCP 吞吐量
W:发生丢失事件时的窗口尺寸 (单位:字节)
- 平均窗口尺寸 (#in-filght 字节):3/4 W
- 平均吞吐量:RTT 事件吞吐 3/4 W
TCP 公平性
公平性目标:如果 K 个 TCP 会话分享一个链路带宽为 R 的瓶颈,每一个绘画的有效带宽为 R/K
为什么 TCP 是公平的
2 个竞争的 TCP 会话:
- 加性增加,斜率为 1,吞吐量增加
- 乘性减,吞吐量比例减少
公平性和 UDP
多媒体应用通常不是 TCP
- 应用发送的数据速率希望不受拥塞控制的节制
使用 UDP:
- 音视频应用泵出数据的速率是恒定的,忽略数据的丢失
研究领域:TCP 友好性
公平性和并行 TCP 连接
2 个主机间可以打开多个并行的 TCP 连接
Web 浏览器
例如:带宽为 R 的链路支持了 9 个连接
- 如果新的应用要求建 1 个 TCP 连接,获得带宽 R/10
- 如果新的应用要求建 11 个 TCP 连接,获得带宽 R/2
Explicit Congestion Notification (ECN)
网络辅助拥塞控制:
- TOS 字段中 2 个 bit 被网络路由器标记,用于只是是否发生拥塞
- 拥塞指示被传送到接收主机
- 在接受方到发送方的 ACK 中,接收方 (在 IP 数据报中看到了拥塞指示)设置 ECE bit,指示发送方发生了拥塞