第三章 传输层
3.1 传输层服务
1. 传输层服务和协议
传输层协议为运行在不同Host上的进程提供了一种逻辑通信机制
所谓逻辑通信是指,两个进程之间仿佛是直接连接的,而无需考虑二者之间有多远的物理距离、二者之间相隔了多少路由器。
端系统运行传输层协议的原理:
✦ 发送方:将应用递交的消息分成一个或多个的segment,并向下传给网络层。
✦ 接收方:将接收到的segment组装成消息,并向上交给应用层。
Segment即报文段。
传输层可以为应用提供多种协议:
✦ Internet上的TCP传输层协议
✦ Internet上的UDP传输层协议
2. 传输层 vs. 网络层
网络层:提供主机之间的逻辑通信机制
传输层:提供应用进程之间的逻辑通信机制位于网络层之上
✦ 依赖于网络层服务
✦ 对网络层服务进行(可能的)增强
可以类比成李雷家和韩梅梅家两个家庭之间发信:
3. Internet传输层协议
可靠、按序的交付服务(TCP)
✦ 拥塞控制
✦ 流量控制
✦ 连接建立
不可靠的交付服务(UDP)
✦ 基于 “尽力而为(Best-effort)” 的网络层,没有做(可靠性方面的)扩展
两种服务均不保证
✦ 延迟
✦ 带宽
3.2 多路复用和多路分用
1. 为什么要多路复用/分用?
如果某层的一个协议对应直接上层的多个协议/实体,则需要复用/分用。
如下例:主机1的P3进程给主机2的P1进程发送数据,主机3的P4进程给主机2的P2进程发送数据。那么主机2的传输层就要完成一个任务:把来自P3进程的数据正确交付给P1,把来自P4的数据正确交付给P2。传输层把收到的segment交付给正确的进程的过程就是多路分用。
与之对应的,在发送数据时,传输层就要完成的任务是:从多个进程接收数据,分别封装头部信息组成segment,再通过网络层发送。这一过程就是多路复用。
2. 分用如何工作?
主机接收到的IP数据报(datagram)中:
✦ 每个数据报携带源IP地址、目的IP地址。
✦ 每个数据报还携带一个传输层的段(Segment)。
✦ 每个段携带源端口号和目的端口号。
主机收到Segment之后,传输层协议提取IP地址和端口号信息,将Segment导向相应的Socket
3. 无连接分用
UDP用二元组来寻找Socket:
✦ 目的IP地址
✦ 目的端口号
主机收到UDP段后:
✦ 检查段中的目的端口号
✦ 将UDP段导向绑定该端口号的Socket
来自不同源IP地址和/或源端口号的IP数据包只要目的IP地址/或目的端口号相投,就会被导向同一个Socket
例:
SP源端口号提供返回地址。
4. 面向连接的分用
TCP用四元组来寻找Socket:
✦ 源IP地址
✦ 源端口号
✦ 目的IP地址
✦ 目的端口号
接收端利用所有的四个值将Segment导向合适的Socket
服务器可能同时支持多个TCP Socket
✦ Web服务器为每个客户端开不同的Socket
例:
来自B主机P2进程和P3进程的数据,只有源端口号不同,但依旧对应两个不同的Socket,这是由于TCP用四元组(源IP地址,源端口号,目的IP地址,目的端口号)来寻找Socket,其根本原因是TCP是点对点的。
如果把TCP换成UDP的话,这两个源端口号不同的数据会被导向同一个Socket,因为UDP用二元组(目的IP地址,目的端口号)来寻找Socket,不考虑源端口号。
例:多线程Web服务器
由于进程耗费资源较多,因此可以让一个进程创建多个线程(相当于轻量级进程),再使用多个线程来建立不同的TCP连接。
服务器C上只有一个进程P4,但是创建了3个线程,通过3个线程就可以为两个客户端上的共3个进程服务。
3.3 无连接传输协议 - UDP
1. UDP简介
基于Internet IP协议添加以下内容:
✦ 复用/分用
✦ 简单的错误校验
链路层也会进行错误校验,为什么要在传输层再进行一次错误校验呢?
一方面,传输层提供的是端到端的逻辑连接服务,在端到端的过程中可能经过很多路由器、很多链路,并不能保证经过的所有链路层都有错误校验机制。另一方面,在距离应用层最近的传输层增加错误校验机制,可以最大限度地保证数据的正确性。
由于UDP几乎把IP协议暴露给了网络层,因此UDP和IP一样都是 “Best effort” 服务
因此UDP段可能:
✦ 丢失
✦ 非按序到达
UDP是无连接的
✦ UDP发送方和接收方之间不需要握手
✦ 每个UDP段的处理独立于其他UDP段
UDP为什么存在?
无需建立连接(减少延迟);
实现简单,无需维护连接状态;
头部开销少;
没有拥塞控制,应用可以更好地控制发送时间和速率。
2. UDP的应用
常用于流媒体应用,因为流媒体应用:
✦ 容忍丢失
✦ 速率敏感
UDP还用于:
✦ DNS
✦ SNMP
如何在UDP上实现可靠数据传输?在应用层实现
✦ 在应用层增加可靠性机制
✦ 应用特定的错误恢复机制
3. UDP报文段格式
源端口号(16bits)、目的端口号(16bits)、UDP段的长度(16bits)、校验和(16bits)、应用数据(报文)。
4. UDP校验和
目的:检测UDP段在传输中是否发生错误(如位翻转)
发送方:
✦ 将段的内容视为16-bit整数
✦ 校验和计算:计算所有整数的和,进位加在和的后面,将得到的值按位求反,得到校验和
✦ 发送方将校验和放入校验和字段
接收方:
✦ 计算所收到段的校验和
✦ 将其与校验和字段进行对比
✦ 不相等:检测出错误;相等:没有检测出错误(但可能有错误)
校验和计算示例:
3.4 可靠数据传输的基本原理
3.4.1 可靠数据传输概述
什么是可靠?
✦ 不错、不丢、不乱
可靠数据传输协议的重要性:
✦ 可靠数据传输对应用层、传输层、链路层都很重要
✦ 是网络Top-10问题
✦ 信道的不可靠特性决定了可靠数据传输协议(rdt)的复杂性
3.4.2 可靠数据传输协议(rdt)基本结构及其接口
从提供服务的角度看,传输层为应用层提供了可靠数据传输服务,就好像提供了可靠信道。从服务实现的角度来说,底层信道实际上是不可靠的,可靠数据传输服务实际上存在于发送端和接收端的传输层之中。
接口如图所示:
注意,rdt_send()的调用是单向箭头,意味着上层网络应用调用一次rdt之后,剩下所有事情都交给rdt来做,deliver_data()也是单向箭头,说明rdt做完所有事情之后,才把数据交付给上层。而udt_send()和rdt_rcv()都是双向的,这意味着在不可靠信道上实现可靠数据传输并不只是简单的单向数据流动,还需要双向的控制信息流动。
3.4.3 可靠数据传输协议(rdt)
下面我们将由简单到复杂渐进地设计可靠数据传输协议的发送方和接收方
✦ Rdt 1.0 → Rdt 2.0 → Rdt 2.1 → Rdt 3.0
只考虑单向数据传输(发送方把数据发给接收方)
✦ 但控制信息双向流动
利用状态机(Finite State Machine, FSM)刻画传输协议
3.4.4 Rdt 1.0: 可靠信道上的可靠数据传输
底层信道完全可靠
✦ 不会发生错误
✦ 不会丢弃分组
由于发送方和接收方之间不需要交流任何控制信息,因此双方的FSM是相互独立的
FSM规约:
发送方:等待上层调用 → 上层调用rdt_send(data)发送数据;调用make_pkt(data)创建分组,调用udt_send(packet)向下层发送分组 → 继续等待上层调用
接收方:等待下层调用 → 下层调用drt_rcv(packet)传来分组;调用extract(packet,data)把数据从分组中提取出来,调用deliver_data(data)向上层交付数据
3.4.5 Rdt 2.0: 产生位错误的信道
底层信道可能翻转分组中的位(bit)
✦ 利用校验和检测位错误
如何从错误中恢复?
✦ 确认机制(Acknowledgements, ACK): 接收方显式地告知发送方分组已正确接收
✦ NAK: 接收方显式地告知发送方分组有错误
✦ 发送方收到NAK后,重传分组
基于这种重传机制的rdt协议称为ARQ(Automatic Repeat reQuest)协议
Rdt 2.0中引入的新机制:
✦ 差错检测
✦ 接收方反馈控制消息:ACK/NAK
✦ 重传
FSM规约:
无错误场景:
有错误场景:
3.4.6 Rdt 2.1和Rdt 2.2
1. Rdt 2.0有什么缺陷?
如果ACK/NAK消息发生错误/被破坏(corrupted)Rdt1.0无法处理
✦ 为ACK/NAK增加校验和,检错并纠错
✦ 发送方收到被破坏ACK/NAK时不知道接收方发生了什么,添加额外的控制消息
✦ 如果ACK/NAK坏掉,发送方重传
✦ 不能简单的重传:产生重复分组
如何解决重复分组问题?
✦ 序列号(Sequence number): 发送方给每个分组增加序列号
✦ 接收方丢弃重复分组
2. Rdt 2.1:处理ACK/NAK发生错误/被破坏
发送方FSM, 应对ACK/NAK破坏:
其中0和1是序列号。
接收方FSM, 应对ACK/NAK破坏:
当接收方等待0号分组,却收到了1号分组时,是什么情况?情况是:上一次的1号分组接收成功,接收方返回ACK,结果ACK损坏了,发送方只好重发1号分组。此使接收方不能置之不理,因为发送方正在等待ACK/NAK;也不能返回NAK,否则发送方又要重发;因此只能再发一遍ACK,把上一个损坏的ACK补上。
3. Rdt 2.1 vs. Rdt 2.0
发送方:
✦ 为每个分组增加了序列号
✦ 两个序列号(0, 1)就够用,为什么?
因为采用的是停等协议,不发完一个分组,不会进入下一个分组
✦ 需校验ACK/NAK消息是否发生错误
✦ 状态数量翻倍(状态必须 “记住” “当前” 的分组序列号)
接收方:
✦ 需判断分组是否是重复(当前所处状态提供了期望收到分组的序列号)
✦ 注意:接收方无法知道ACK/NAK是否被发送方正确收到
4. Rdt 2.2: 无NAK消息协议
我们真的需要两种确认消息(ACK + NAK)吗?不!
Rdt 2.2与rdt 2.1功能相同,但是只使用ACK
如何实现?
✦ 接收方通过ACK告知最后一个被正确接收的分组
✦ 在ACK消息中显式地加入被确认分组的序列号
发送方收到重复ACK之后,采取与收到NAK消息相同的动作:重传当前分组
Rdt 2.2 FSM片段:
3.4.7 Rdt 3.0
1. Rdt 3.0
如果信道既可能发生错误,也可能丢失分组,怎么办?
方法:发送方等待“合理”时间
✦ 如果没收到ACK,重传
✦ 如果分组或ACK只是延迟而不是丢了:
重传会产生重复,序列号机制能够处理
接收方需在ACK中显式告知所确认的分组
✦ 需要定时器
发送方FSM
Rdt 3.0示例:
注意最后一种超时时间设置过短的情况,从超时开始,发送方重发pkt1,而上一个pkt1的ACK1才姗姗来迟,让发送方以为第二个pkt1已经成功送达,因此会发送下一个分组,即pkt0,这时第二个pkt1的ACK1发来了,但是发送方想要的是ACK0,因此发送方会以为pkt0损坏了,所以会再发一次pkt0,这时第一个pkt0的ACK0才姗姗来迟,让发送方以为第二个pkt0已经成功送达,因此会发送下一个分组,即pkt1……
如此无限循环下去,可以看到,Rdt 3.0可以完成发送数据的任务,但是所有分组都发送了两遍,效率折半。
2. Rdt 3.0性能分析
Rdt 3.0能够正确工作,但性能很差
示例:1Gbps链路,15ms端到端传播延迟,1KB分组,传输延迟:
✦ 发送方利用率:发送方发送时间百分比
在1Gbps链路上每30毫秒才发送一个分组 → 33KB/sec
网络协议限制了物理资源的利用(设计时要考虑软硬件协同,性能要相匹配)
3. Rdt 3.0: 停等操作
4. 流水线机制:提高资源利用率
流水线协议:打破停等协议,允许发送方在收到ACK之前连续发送多个分组
✦ 更大的序列号范围
✦ 发送方和/或接收方需要更大的存储空间以缓存分组(所有发出去但还未确认的分组)
3.5 滑动窗口协议
要想实现流水线机制,就要使用滑动窗口协议。
3.5.1 滑动窗口协议概述
窗口:
✦ 窗口大小决定了允许使用的序列号范围
✦ 窗口尺寸为N:最多有N个等待确认的消息
滑动窗口:
✦ 随着协议的运行,窗口在序列号空间内向前滑动
✦ 绿色为已经发送完并且成功确认的;黄色为已经发出但未确认的
✦ 蓝色代表还可以使用的序列号
滑动窗口协议有:GBN, SR
3.5.2 GBN: Go-Back-N协议
1. 发送方
分组头部包含k-bit序列号(一共有2
k
^k
k个序列号可以用)
窗口尺寸为N,最多允许N个分组未确认
ACK(n): 确认到序列号n(包含n)的分组均已被正确接收(累计确认机制)
✦ 可能收到重复ACK
为空中的分组设置计时器(timer)
✦ 超时Timeout(n)事件: 重传序列号大于等于n,还未收到ACK的所有分组
发送方扩展FSM:
2. 发接收方
ACK机制: 发送拥有最高序列号的、已被正确接收的分组的ACK
✦ 可能产生重复ACK
✦ 只需要记住唯一的expectedseqnum(期望收到分组)
乱序到达的分组:
✦ 直接丢弃 → 接收方没有缓存
✦ 重新确认序列号最大的、按序到达的分组
接收方扩展FSM:
3. GBN示例
接收方收到pkt3会直接丢弃掉。
3.5.3 SR: Selective Repeat协议
1. 对GBN进行改进
接收方对每个分组单独进行确认
✦ 设置缓存机制,缓存乱序到达的分组
发送方只重传那些没收到ACK的分组
✦ 为每个分组设置定时器
2. 发送方/接收方窗口
在发送方窗口的基础上,新增接收方窗口
3. 发送方/接收方具体事件
4. SR协议示例
5. SR协议的困境
SR协议的接收方并不能分清楚下面这两种情况:
解决办法:序列号空间大小与窗口尺寸需满足:
✦ N
S
_S
S + N
R
_R
R <= 2
k
^k
k
✦ 发送方窗口大小 + 接收方窗口大小 <= 序列号总数
3.6 面向连接传输协议-TCP
3.6.1 TCP概述
1. TCP的特点
(1) 点对点
★ 一个发送方,一个接收方
(2) 可靠的、按序的字节流
(3) 流水线机制
★ TCP根据拥塞控制和流量控制机制设置窗口尺寸
(4) 发送方/接收方缓存
★ 从这一特点来说,TCP类似于滑动窗口协议中的SR
(5) 面向连接
★ 通信双方在发送数据之前必须建立连接
★ 连接状态只在连接的两端中维护,在沿途节点中并不维护状态
★ TCP连接的数据包括:两台主机上的缓存、连接状态变量、socket等,双方共同维护这些数据
(6) 提供流量控制机制和拥塞控制机制
(7) 全双工(full-duplex)
★ 同一连接中能够传输双向数据流
2. TCP的段结构
3. 序列号和ACK
(1) 序列号
★ 序列号指的是segment中第一个字节的编号,而不是segment的编号
☆ 举例: 若共1000B数据,分为两段,那么第一个段的序列号为0,第二个段的序列号为500
★ 建立TCP连接时,双方随机选择序列号进行交换数据
(2) ACK
★ 希望接收到的下一个字节的序列号
★ 使用累计确认机制:该序列号之前的所有字节均已被正确接收到
☆ 从这一点上看,TCP类似于窗口滑动协议中的GBN
(3) 问题:接收方如何处理乱序到达的Segment?
★ A: TCP规范中没有规定,由TCP的实现者做出决策
4. 举例
两台主机上运行远程通路(telnet)的应用:
① 用户A输入字符’C’,产生TCP段,该段序列号为42,ACK为79
② 用户B回传字符’C’,产生TCP段,该段序列号为79,ACK为43
☆ A传送来的段的序列号为42,且只传了一个字符,因此下一个字节序号应为43
☆ 传回该消息代表着序列号在43之前的数据都已经成功收到
③ 用户A再次发送消息,不仅发送了数据,也是对B发给A的消息②的一种确认
3.6.2 TCP可靠数据传输
1. TCP可靠数据传输概述
(1) TCP在IP层提供的不可靠服务基础上实现可靠数据传输服务
(2) 使用流水线机制提高性能
(3) 使用累积确认机制
(4) TCP使用单一重传定时器
★ 在这一点上异于SR,SR为每个分组都设置一个定时器,而TCP一共只有一个定时器
(5) 触发重传的事件
★ 超时
★ 收到重复ACK
(6) 考虑到学习的渐进式,这一小节并不完整
★ 暂不考虑重复ACK
★ 暂不考虑流量控制
★ 暂不考虑拥塞控制
2. RTT和超时
要想处理丢失,就需要设置定时器的超时。
问题:那么定时器的超时设置为多少才是合理的?
(1) 超时应该大于RTT
★ 但是RTT是根据网络情况变化的,超时应该大于RTT多少呢?
(2) 超时过短:会发生不必要的重传
(3) 超时过长:对段丢失时间反应慢
问题:如何估计RTT?
(1) SampleRTT: 不停测量从段发出去到收到ACK的时间,作为RTT
★ 忽略重传
(2) SampleRTT肯定是在变化的
★ 测量多个SampleRTT,求平均值,形成RTT的估计值EstimatedRTT
★ 采用指数加权平均
问题:定时器超时时间的设置
(1) EstimatedRTT + “安全边界”
★ EstimatedRTT变化大 → 较大的边界
★ EstimatedRTT的变化反映了网络状况
(2) 测量RTT的变化值: SampleRTT与EstimatedRTT的差值
(3) 定时器超时时间的设置:
3. TCP发送方事件
(1) 从应用层收到数据后
★ 创建Segment
★ 序列号是Segment第一个字节的编号
★ 开启计时器
★ 设置超时时间: TimeOutInterval
(2) 如果发生超时
★ 重传引起超时的那一个Segment
★ 重启定时器
(3) 收到ACK后
★ 如果确认了此前未确认的Segment
☆ 更新SendBase(滑动窗口的基序号)
☆ 如果窗口中还有未被确认的分组,重新启动定时器
4. TCP发送端程序
5. TCP重传示例
(1) 丢失ACK的场景
★ A发送段,序列号为92,内有8字节数据
★ B收到数据,发送ACK,序列号100 (92+8)
★ ACK丢失,发生TimeOut事件
★ A重传序列号为92的段
★ B收到数据,发送ACK
★ A将SendBase更新为100
(2) 超时时间设置得太短
★ A发送段,序列号为92,内有8字节数据
★ 紧接着,A发送段,序列号为100,内有20字节数据
★ B收到数据,发送ACK,序列号100 (92+8)
★ 紧接着,B收到数据,发送ACK,序列号120 (100+20)
★ 不幸的是,超时时间过短,ACK还未到达,就已超时
★ A重传序列号为92的段
★ 由于TCP是累计确认机制,B发送ACK的序列号为120
(3) 超时时间设置得太长
★ A发送段,序列号为92,内有8字节数据
★ 紧接着,A发送段,序列号为100,内有20字节数据
★ B收到数据,发送ACK,序列号100 (92+8)
★ 紧接着,B收到数据,发送ACK,序列号120 (100+20)
★ 序列号为100的ACK丢失了,但是超时时间过长,序列号为120的ACK到来了
★ 由于TCP是累计确认机制,A可以确认序列号在120之前的数据均已送达
5. TCP接收端ACK生成的过程
6. 快速重传机制
(1) TCP的实现中,如果发生超时,超时时间间隔将重新设置,即将超时时间间隔加倍,导致其很大
★ 这样并不好:重发丢失的分组之前要等待很长时间
(2) 通过重复ACK检测分组丢失
★ Sender会背靠背地发送多个分
★ 组如果某个分组丢失,可能会引发多个重复的ACK
(3) 如果sender在已经收到某个数据的ACK之后,又接收到同一数据的3个ACK,则假定该数据之后的段已经丢失
★ 快速重传:在定时器超时之前即进行重传
7. 快速重传算法
3.6.3 TCP流量控制
1. 为什么有流量控制
★ 数据从网络层传到传输层后,接收方为TCP连接分配buffer(缓存)
★ 上层应用处理buffer中数据的速度可能较慢
★ 发送方不会传输的太多、太快以至于淹没接收方(buffer溢出)
★ 因此流量控制实质上是一种速度匹配机制
2. 流量控制如何实现
★ (假定TCP receiver丢弃乱序的segments)
★ Buffer中的可用空间(spare room)
★ Receiver通过在Segment 的头部字段将RcvWindow告诉Sender
★ Sender限制自己已经发送的但还未收到ACK的数据不超过接收方的空闲RcvWindow尺寸
★ Receiver告知Sender RcvWindow=0,会出现什么情况?
☆ 若Sender不再发送数据,就算Receiver已经有了空闲的RcvWindow,也无法通过ACK告知Sender,因此Sender在Receiver RcvWindow=0时,依旧会不断发送一个数据量很小的段
3.6.4 TCP连接管理
1. TCP连接管理:建立
TCP sender和receiver在传输数据前需要建立连接
(1) 初始化TCP变量
★ 选择序列号Seq#
★ 分配缓存Buffer,交换流量控制信息
(2) Client:连接发起者新建Socket
★ Socket clientSocket = new Socket(“hostname”,“port number”);
(3) Server: 等待客户连接请求并接收请求
★ Socket connectionSocket = welcomeSocket.accept();
(4) TCP连接采用三次握手机制
★ 客户主机向服务器发送SYN报文段
☆ SYN标志位置为1表示请求建立连接
☆ 指定初始序列号
☆ 不携带任何数据
★ 服务器接收SYN,回复SYNACK报文段
☆ 分派缓存buffer
☆ 指定服务器初始序列号
★ 客户接受SYNACK,回复ACK
☆ 客户告知服务器客户已经知道服务器同意连接
(5) 为什么采用3次握手而不是2次?
考虑以下情况:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。
2. TCP连接管理:关闭
用户使用 clientSocket.close() 函数关闭连接
(1) 用户向服务器发送FIN报文
☆ 类似于SYN,FIN也是一个标志位
(2) 服务器收到FIN,回复ACK;关闭连接,发送FIN
(3)用户收到FIN, 回复ACK
☆ 这过程需要进入“等待”,如果再收到FIN,会重新发送ACK
(4) 服务器收到ACK,连接关闭
3. TCP连接生命周期
(1) TCP连接用户生命周期
(2) TCP连接服务器生命周期
3.7 拥塞控制原理
3.7.1 拥塞的成因和代价
1. 拥塞概述
(1) 非正式定义:“太多发送主机发送了太多数据或者发送速度太快,以至于网络无法处理”
(2) 拥塞的表现
★ 分组丢失(路由器缓存溢出)
★ 分组延迟过大(在路由器缓存中排队)
(3) 流量控制 vs. 拥塞控制
★ 可靠数据传输
☆ 是从个体角度出发的
☆ 针对端到端的传输层连接
☆ 发送端不要发送太快以至于接收端处理不了
★ 拥塞控制
☆ 是从群体角度出发的,目标是群体利益最大
☆ 发送端不要发送太快以至于网络处理不了
2. 拥塞的成因和代价:场景1
(1) 背景
★ 两个senders,两个receivers
★ 一个路由器, 无限缓存
★ 链路速率为C
★ 没有重传
★
λ
i
n
\lambda_{in}
λin定义A/B发送速率,
λ
o
u
t
\lambda_{out}
λout定义C/D接受速率
(2) 效果
★ 拥塞所带来的代价:分组延迟太大
3. 拥塞的成因和代价:场景2
(1) 背景
★ 两个senders,两个receivers
★ 一个路由器, 有限缓存
★ 链路速率为R
★ 可能重传
★
λ
i
n
\lambda_{in}
λin定义A/B发送速率,
λ
o
u
t
\lambda_{out}
λout定义C/D接受速率
★
λ
i
n
′
\lambda_{in}'
λin′代表在考虑重传的条件下,实际有效的发送速率
(2) 几种情况
★ 情况a: Sender能够通过某种机制获知路由器buffer信息,有空闲才发
λ
i
n
′
=
λ
i
n
=
λ
o
u
t
\lambda_{in}'=\lambda_{in}=\lambda_{out}
λin′=λin=λout
☆ 显然
λ
i
n
<
R
2
\lambda_{in}<\frac{R}{2}
λin<2R,否则buffer不可能有空闲
★ 情况b: 丢失后才重发,由于考虑到了重发,实际有效发送速率有所降低,即
λ
i
n
′
>
λ
o
u
t
\lambda_{in}'>\lambda_{out}
λin′>λout
★ 情况c: 分组丢失和定时器超时后都重发,重发次数增加,
λ
i
n
′
\lambda_{in}'
λin′变得更大
(3) 效果
★ 拥塞所带来的代价:由于延迟很高,所以重传次数很多,浪费资源
4. 拥塞的成因和代价:场景3
(1) 背景
★ 四个发送方
★ 多跳,多个路由器均为有限缓存
★ 链路速率为C
★ 分组丢失和定时器超时后都重发
★
λ
i
n
\lambda_{in}
λin定义A/B发送速率,
λ
o
u
t
\lambda_{out}
λout定义C/D接受速率
★
λ
i
n
′
\lambda_{in}'
λin′代表在考虑重传的条件下,实际有效的发送速率
(2) 效果
★ 主机A经过两个路由器给主机C发送数据
★ 同时,主机D经过两个路由器给主机B发送数据
★ 因此,图中红线、绿线会在路由器R2处发生竞争
★ 由于竞争,会发生拥塞,因此会造成不断地丢失
★ 最关键的是,在R2处丢失的数据,实际上已经经过了其他路由器的处理
★ 因此,每一次丢失都是巨大资源的浪费
★ 拥塞的另一个代价: 当分组被丢掉时,任何用于该分组的“上游”传输能力全都被浪费掉
3.7.2 拥塞控制原理
由于拥塞是“太多发送主机发送了太多数据或者发送速度太快,以至于网络无法处理”,那么最直观的想法就是: 限制发送方的发送速率。
1. 拥塞控制的方法
(1) 端到端拥塞控制:
★ 网络层(路由器等)不需要显式的提供支持
★ 端系统通过观察loss,delay等网络行为判断是否发生拥塞
★ 端系统控制自己的发送速率
★ TCP采取这种方法
(2) 网络辅助的拥塞控制:
★ 路由器向发送方显式地反馈网络拥塞信息
★ 端系统依据路由器发来的消息调整自己的发送速率
★ 简单的拥塞指示(1bit):SNA,DECbit,TCP/IP ECN,ATM
★ 指示发送方应该采取何种速率
2. 案例:ATM ABR拥塞控制
(1) ATM简介
ATM是Asynchronous Transfer Mode(ATM)异步传输模式的缩写,是以信元(Cell)为基础的一种分组交换和复用技术。
ATM采用面向连接的传输方式,将数据分割成固定长度的信元(Cell),通过虚连接进行交换。ATM集交换、复用、传输为一体,在复用上采用的是异步时分复用方式,通过信息的首部或标头来区分不同信道。
(2) ABR:available bit rate
★ “弹性服务”
★ 如果发送方路径“underloaded”: 尽可能使用可用带宽
★ 如果发送方路径拥塞: 将发送速率降到最低保障速率
(3) RM(resource management) cells
★ 由发送方发送
★ 在交换机处设置RM cell位(因此叫做网络辅助)
☆ NI bit: rate不许增长
☆ CI bit: 拥塞指示
★ RM cell由接收方返回给发送方
(4) 实例
★ 在RM cell中有显式的速率(ER)字段: 两个字节;NI和CI为定性指示,而ER为定量指示
☆ 拥塞的交换机可以将ER置为更低的值
☆ 发送方获知路径所能支持的最小速率
★ 数据cell中的EFCI位: 拥塞的交换机将其设为1
☆ 如果RM cell前面的data cell的EFCI位被设为1,那么发送方在返回的RM cell中置CI位
3.8 TCP拥塞控制
3.8.1 TCP拥塞控制
1. TCP拥塞控制的基本原理
(1) Sender限制发送速率
L
a
s
t
B
y
t
e
S
e
n
t
−
L
a
s
t
B
y
t
e
A
c
k
e
d
⩽
C
o
n
g
W
i
n
LastByteSent-LastByteAcked\leqslant CongWin
LastByteSent−LastByteAcked⩽CongWin
(2) CongWin(变量: 拥塞窗口数量):
★ 动态调整以改变发送速率
★ 反映所感知到的网络拥塞
(3) 问题:如何感知网络拥塞?
★ Loss事件 = timeout 或 3个重复ACK
★ 发生loss事件后,发送方降低速率
(4) 如何合理地调整发送速率?
★ 加性增—乘性减: AIMD
★ 慢启动: SS(SlowStart)
2. 加性增—乘性减: AIMD
(1) 原理:逐渐增加发送速率,谨慎探测可用带宽,直到发生Loss事件
(2) 方法: AIMD
★ Additive Increase: 每个RTT将CongWin增大一个MSS(最大段长度)——拥塞避免
★ Multiplicative Decrease: 发生Loss后将CongWin减半
3. TCP慢启动: SS
(1) TCP连接建立时,CongWin=1
★ 例:当MSS=500 byte, RTT=200msec时,初始速率只有20k bps
(2) 可用带宽可能远远高于初始速率:
★ 希望CongWin快速增长
(3) 原理:
★ 当连接开始时,CongWin指数性增长(有多少segment,CongWin就增加多少)
(4) 指数性增长
★ 每个RTT内,都会将CongWin翻倍
★ 翻倍的原理是:每收到一个ACK,CongWin就加一
★ 初始速率很慢,但是快速攀升
4. Threshold变量
(1) 问: 何时应该指数性增长切换为线性增长(拥塞避免)?
答: 当CongWin达到Loss事件前值的1/2时
(2) 实现方法(以下图为例):
★ 初始时先随意确定一个阈值Threshold(8)
★ 经历过一次Loss后,就可以更新Threshold(6)
★ 在TCP Tahoe版本中,遇到Loss情况会将CongWin降低为最小值,再从头开始指数增长、线性增长
★ 这样可能过于保守了,因此后来采用乘性减的Reno版本
5. Reno版本的Loss事件的处理
(1) 收到3个重复ACKs:
★ CongWin减为一半
★ 然后线性增长
(2) Timeout事件:
★ CongWin直接设为1个MSS
★ 然后指数增长
★ 达到Threshold后, 再线性增长
(3) 原理
★ 3个重复ACKs表示网络还能够传输一些segments
★ timeout事件表明拥塞更为严重
6. TCP拥塞控制: 总结
(1) 当CongWin小于Threshold时,发送方处于慢启动阶段,CongWin呈指数型增长
(2) 当CongWin大于Threshold时,发送方处于拥塞避免阶段,CongWin呈线性增长
(3) 当收到3个重复ACK时,Threshold应该减为CongWin的一半,CongWin也减为原来的一半
(4) 当发生拥塞时,Threshold应该减为CongWin的一半,CongWin减为1MSS
7. 例题
一个TCP连接总是以1 KB的最大段长发送TCP段,发送方有足够多的数据要发送。当拥塞窗口为16 KB时发生了超时,如果接下来的4个RTT(往返时间)时间内的TCP段的传输都是成功的,那么当第4个RTT时间内发送的所有TCP段都得到肯定应答时,拥塞窗口大小是多少?
解:threshold=16/2=8 KB,CongWin=1 KB,1个RTT后,CongWin=2 KB,2个RTT后, CongWin=4 KB,3个RTT后,CongWin=8 KB,Slowstart is over;4个RTT后,CongWin=9 KB
3.8.2 TCP性能
1. TCP throughput: 吞吐率
忽略掉Slow start
★ 假定发生超时时CongWin的大小为W,吞吐率是W/RTT
★ 超时后,CongWin=W/2,吞吐率是W/2RTT
★ 平均吞吐率为: 0.75W/RTT
2. 未来的TCP
(1) 举例:每个Segment有1500个byte,RTT是100ms,希望获得10Gbps的吞吐率
★ throughput = W×MSS×8/RTT, 则
★ W = throughputRTT/(MSS8)
★ throughput = 10Gbps,则W = 83,333
★ 窗口大小为83,333
(2) 吞吐率与丢包率(loss rate, L)的关系
★ CongWin从W/2增加至W时出现第一个丢包
★ 这段时间内一共发送的分组数为
W
2
+
(
W
2
+
1
)
+
(
W
2
+
2
)
+
…
.
+
W
=
3
W
2
8
+
3
W
4
\frac{W}{2} + (\frac{W}{2}+1) + (\frac{W}{2}+2) +….+ W = \frac{3W^2}{8} + \frac{3W}{4}
2W+(2W+1)+(2W+2)+….+W=83W2+43W
★ W很大时,
3
W
2
8
\frac{3W^2}{8}
83W2 >>
3
W
4
\frac{3W}{4}
43W,因此
L
≈
3
W
2
8
L ≈ \frac{3W^2}{8}
L≈83W2
★
★ L =
2
×
1
0
−
10
2×10^{-10}
2×10−10
★ 这样小的分组对链路和路由器的要求非常非常高,高到已经不现实
(3) 高速网络下需要设计新的TCP
3. TCP的公平性
(1) 公平性: 如果K个TCP Session共享相同的瓶颈带宽R,那么每个Session的平均速率为R/K
(2) TCP具有公平性吗?是的!
★ 在最开始,主机1和主机2的带宽可能是不一样的
★ 但是在线性增长阶段,主机1和主机2的CongWin增长速度是一致的,在图中表现为图线45°斜向上延伸
★ 直到收到3个重复的ACK,CongWin减半,在图中表现为图线向原点延伸
★ 不断重复该过程,最终图线会收敛于中间的平等带宽共享的线
(3) 公平性与UDP
★ 多媒体应用通常不使用TCP,以免被拥塞控制机制限制速率
★ 使用UDP:以恒定速率发送,能够容忍丢失
★ 但UDP不遵守拥塞控制机制,因而产生了不公平
★ 所以需要研究出TCP友好的UDP机制
(4) 公平性与并发TCP连接
★ 某些应用会打开多个并发连接,例如Web浏览器
★ 这样也会产生公平性问题
★ 例子:链路速率为R,已有9个连接
☆ 新来的应用请求1个TCP,获得R/10的速率
☆ 新来的应用请求11个TCP,获得R/2的速率