第三章 运输层
运输层与网络层:将网络层的在两个端系统之间的交付服务扩展到运行在两个不同端系统上的应用层进程之间的交付服务。
3.1 概述和运输层服务
逻辑通信:运行不同进程逻辑直连。(运输层在应用程序进程间提供逻辑的而非物理的通信)
数据传输过程: 运输层协议在端系统中而不是在路由器中实现的
-
发送端
应用程序报文→运输层报文段(segment)(运输层将应用报文划分为较小的块,并为每一块加上运输层首部)→网络层接受传输层报文段,将其封装成网络层分组(即数据报)并向目的地发送
-
接收端
网络层从数据报中提取运输层报文段,并将该报文段向上交给运输层,运输层则处理接收到的报文段,使该报文段中的数据为接收应用进程使用
3.1.1 运输层与网络层的关系
-
在协议栈中,运输层刚好位于网络层之上。网络层提供了主机之间的逻辑通信,而运输层为运行在不同主机上的进程之间提供了逻辑通信。
-
运输层协议只工作在端系统。在端系统中,运输层协议将来自应用进程的报文移动到网络边缘(即网络层),反过来也是一样,但对有关这些报文在网络核心如何移动并不作任何规定。
-
运输协议能够提供的服务常常受制于底层网络层协议的服务模型。如果网络层协议无法为主机之间发送的运输层报文段提供时延或带宽保证的话,运输层协议也就无法为进程之间发送的应用程序报文提供时延或带宽保证。
(注:即使底层网络协议不能在网络层提供相应的服务,运输层协议也能提供某些服务)
3.1.2 因特网运输层概述
(1) 网络层协议:
-
IP(网际协议)—— 不靠谱服务
IP的服务模型是尽力而为交付服务。意味着:不做任何确保,不确保报文段的交付,不保证报文段的按序交付, 不保证报文段中数据的完整性。
(2) 运输层协议:
-
UDP (用户数据报协议)
-
TCP (传输控制协议)
提供可靠性数据传输;拥塞控制;流量控制;
-
UDP与TCP都不能提供延时和带宽保证
3.2 多路复用与多路分解
一个进程有一个或多个套接字,一个主机上可以运行多个进程,当运输层从底层的网络层接受数据时,需要将所接收到的数据定向到各个进程。通过套接字来进行定向。
-
多路分解——(运输层→套接字)
将运输层报文段中的数据交付到正确的套接字的工作称为多路分解
在主机上的每个套接字能够分配一个端口号,当报文段到达主机时,运输层检查报文段中的目的端口号,并将其定向到相应的套接字。然后报文段中的数据通过套接字进入其所连接的进程。
-
多路复用——(套接字→运输层)
在源主机从不同套接字中收集数据块,并为每个数据块封装上首部信息(IP地址和端口号,这将在以后用于分解)从而生成报文段,然后将报文段传递到网络层。
-
运输层的报文段
源IP地址和目的IP地址在数据报中(网络层)
-
无连接的多路复用与多路分解
(1) UDP套接字的创建
UDP套接字由二元组
(目的IP地址, 目的端口号)
标识(也就是在传输数据时只需要指明目的IP地址和目的端口号即可)(2) 多路分解
具有相同的目的IP和端口的报文将会经过相同的目的套接字被定向到相同的目的进程
(3) 多路复用
-
面向连接的多路复用与多路分解
(1) TCP套接字的创建
TCP套接字由四元组
(源IP地址, 源端口号, 目的IP地址, 目的端口号)
。(2) 多路分解
与UDP不同,TCP只要是不同的源(不同IP或端口)就会被定向到不同的套接字(只有四元组的每个值都匹配才会分解到相同的套接字)。
通过这四个值来讲报文段定向到相应的套接字
其中一个进程对应了一个端口,每次当有一个新的连接时,就会创建一个新的线程来为新的连接服务,通过4元组可以将报文段的内容重定向到不同的线程。
(3) 多路复用
-
Web服务器与TCP
-
客户向服务器发送报文段时,初始连接建立报文段和承载 HTTP 请求的报文段都有 80 的目的端口
-
连接套接字与进程之间并非总一一对应,一个进程可以有多个线程,会为每个线程分配新的套接字
-
3.3 无连接运输:UDP
提供复用/分解以及少量的差错检测,也就是说提供了基本的运输层服务(进程到进程之间的传输,以及少量的差错检测)
-
UDP工作过程:
从应用进程得到数据→附加上用于多路复用/分解服务的源和目的端口号字段,以及其他两个小字段,交给网络层→网络层将运输层报文封装到一个IP数据包→到达接收主机→网络层将数据交给传输层→UDP根据目的端口号将数据交给对应的进程。
-
优点:
- 关于发送什么数据以及何时发送的应用层控制更为精细
- 无须连接建立
- 无连接状态
- 分组首部开销小
-
问题
-
丢失
-
乱序
-
UDP没有拥塞控制,可能会导致UDP发送方和接收方之间的高丢包率,如果UDP和TCP使用同一个链路,还会挤垮TCP会话。为了确保TCP会话的稳定和可靠传输,有时候会对UDP流量进行限制或阻塞,以减少对网络链路的拥塞和影响。
-
注:应用进程可以进行可靠通信,而无须受制于由 TCP 拥塞控制机制强加的传输速率限制,也就是说可以在应用层为UDP增加可靠性和差错恢复。
3.3.1 UDP报文段结构
-
首部
包含四个字段,每个字段由两个字节组成
-
端口号
数据→目的端系统中的相应进程(分解功能)
-
长度
UDP 报文段中的字节数——首部字节+数据字节
-
检验和
检查报文段是否出现了差错
-
-
数据字段包含了应用层的数据
3.3.2 UDP检验和
差错检测,用于确定当 UDP 报文段从源到达目的地移动时,其中的比特是否发生了改变。
首部由四个16比特字的数据组成,其中检核和 = ~ (源端口号+目的端口号+长度),最高位的进位需要进行回卷,再加到结果上。将四个部分加起来应为:1111111111111111
。如果出现了0,那就是出现了差错。
为什么要提供UDP检验和?
- 链路可靠性无法保证
- 内存中的差错检测无法保证,链路中只能保证之间相连的设备之间的通信(还是有点儿不懂在内存中是怎么出现差错,以及链路如何保证不出差错)
- → 在端到端的基础上在运输层提供差错检测
实现
- 丢弃受损报文段
- 将受损报文段交给应用程序并发出警告
3.4 可靠性数据传输原理
可靠数据传输
- 上层实体提供的服务:数据可以通过可靠的信道进行传输
- 下层协议也许不可靠,较低层——不可靠的点对点信道
3.4.1 构建可靠数据传输协议
有限状态机(FSM)
箭头指示了协议从一个状态变迁到另一个状态,引起变迁的事件显示在表示变迁的横线上方,事件发生时所采取的动作显示在横线下方。在横线上方或下方使用符号, 以分别明确地表示缺少动作或事件。
-
经完全可靠信道的可靠数据传输:rdt1.0
假设:下层信道完全可靠,没有比特出错以及分组丢失
发送方和接收方的(FSM)
-
发送方
通过rdt_send接收来自高层的数据,将分组发送到信道中。
-
接收方
通过rdt_rcv从底层信道接收一个分组,将数据上传给较高层。
因为有了完全可靠的信道,接收端就不需要提供任何反馈信息给发送方
-
-
经具有比特差错信道的可靠数据传输: rdt2. 0
假设:下层信道可能出错(出现比特翻转),但是所有的分组都能够按其发送的顺序被接收。
由于可能会出现差错,需要采用差错控制编码进行差错检测。
- 发送方:差错控制编码(检验和)、缓存分组用于重发
- 接收方:编码检错、差错反馈
(1) 自动重传请求协议(ABQ)
-
差错检测
接收方检测到何时出现了比特差错
-
接收方反馈
由于发送方和接收方通常运行在不同的端系统上,接收方需要为发送方提供明确的反馈信息。
接收方→
ACK(1) / NAK(0)
→发送方 -
重传
接收方收到有差错的分组时,发送方将重传该分组文
(2) 发送方和接收方的(FSM)
- 发送方
有两个状态,初始状态为左边的状态,当接收到来自上层的调用时(rdt_send),发送方产生一个包含数据的分组(make_pkt),然后将该分组发往接收方(udt_send)。完成这一步之后就进入了右边的状态,等待来着接收方的ACK/NAK。
等待时:ACK→回到左侧状态,等待上层调用;NAK→数据重发。停等协议:在发送方确定接收方已成功接收到当前分组之前,发送方将不会发送一块新数据。
- 接收方
只有单一状态,根据收到的分组是否受损,回答ACK/NAK。
(3) ACK/NAK受损
- 发送方要求接收方复述其回答
- 增加足够的检验和比特
- 重传当前数据分组,在发送方到接收方的信道中引入冗余分组,接收方可能无法知道接收到的分组是新的还是
重传。需要对分组进行编号(0或1),让接收方能够区分是否和上一个接收到的分组一样即可。
(4) rdt2.1
用于解决rdt2.0中存在的问题:ACK/NAK出错的问题,引入新的机制:序号
对于停等协议,完成了一个数据的传输之后才会进行下一个数据的传输,数据按序传输,用一个bit来对当前数据和下一个数据进行区分即可。
发送方:
- 发送来自上层的数据,对数据进行包装(加上分组序号)
- 进入等待状态
- 接收到准确的ACK→等待下一个应用层数据
- 接收到NAK或者不准确的回答,重发数据包。
接收方:
- 等待接收数据,有差错分组→NAK,无差错分组,但是不是所等待的分组(出现了冗余分组)→继续等待,并给发送方ACK
- 无差错且是目标分组→ACK,转移到等待下一个分组的状态
(5) rdt2.2
将rdt2.1中的NAK去掉了,通过为ACK编号实现区分
为ACK报文加上了分组序号,标识接收到了哪个分组的数据。这样能够更好的便于发送端判断是冗余分组被接收还是新的分组被接收,对最后正确接收到的数据发送ACK。
假设要接收的分组时1,如果发现是接收了其他冗余分组0,保险起见,会重发这个分组1。
-
经具有比特差错的丢包信道的可靠数据传输: rdt3. 0
除了比特受损之外,底层信道还会丢包
-
怎么检测丢包?
实践中采取的方式是是发送方明智地选择一个时间值,以判定可能发生了丢包,如果在这个时间内没有收到 ACK, 则重传该分组。
时间值的选择至少:即发送方与接收方之间的一个往返时延(可能会包括在中间路由器时延)加上接收方处理一个分组所需的时间。
为了实现基于时间的重传机制,需要一个倒计数定时器,在给定的时间量过期后,中断发送方。
-
发生丢包之后该做什么?
使用检验和、序号、ACK 分组和重传等
-
发送方FSM
由于rdt3.0是一个停等协议,分组序号会在0和1之间交替——比特交替协议。具体有以下几种情况:
- 无丢包的正常情况
- 分组丢失,接收端只接收到一次分组,相应的也就只会有一次ACK
- ACK丢失,接收端会受到多个相同分组,但是ACK只有一个
- 过早超时,接收端会接收到多个相同分组,发送端也会接收到多个ACK
-
3.4.2 流水线可靠数据传输协议
rdt存在的问题就是它是一个停等协议,信道利用率不高,网络吞吐量低。
采用流水线技术可靠数据传输协议:
- 需要增加序号的范围。序号用于区别不同的分组,由于在流水线技术中的一次性传输的分组数量变多了,所以需要将序号的范围扩大。
- 协议的发送方和接收方需缓存多个分组。发送方需缓存已发送还没确认的分组,接收方需缓存已正确接收的分组。
3.4.3 回退N步(GBN)——滑动窗口协议
允许发送方发送多个分组而不许等待确认,受限于在流水线中未确认的分组数不能超过某个最大的允许数N。
-
GBN协议的序号范围
基序号:最早未确认分组的序号下一个序号:最小的未使用序号(下一个待发分组的序号)
窗口长度N:流水线中的分组数限制
[0, base - 1]
:已经发送并确认[base, nextseqnum-1]
:已经发送未确认[nextseqnum, base + N -1]
:要求被立即发送的分组[base+N, ∞]
:这部分序号不能使用,除非当前流水线中的未被确认的分组已经得到了确认。 -
GBN的扩展FSM
发送方
-
上层的调用
上层调用rdt_send,发送方检查发送窗口是否已满。未满→发送该新的分组,已满→不发送
-
收到ACK
累积确认
对于收到的模糊不清的ACK,不做处理,等待下一个清晰的ACK出现或者等待超时出现
-
超时事件
出现超时,发送方重传所有已发送但还没确认过的分组。如果接收到了一个ACK但是仍然还有未被确认的分组,那么会重启计时器
接收方
-
累积确认: 如果分组k已接收并交付,那么所有序号比k小的分组页已经交付。在非正确接收情况下,接收方丢弃该分组,并为最近按序接收的分组重新发送 ACK
-
接收方会丢弃所有的失序分组,不需要缓存任何的时许分组,需要维护的唯一信息是下一个按序接收的分组的序号
expectedseqnum
。
3.4.4 选择重传(SR)
不重传所有的已发送还没确认的分组,仅重传那些它怀疑接收方出错的分组。
SR接收方将确认一个正确接收的分组而不管其是否按序。失序的分组将被缓存直到所有丢失分组(即序号更小的分组 )皆被收到为止。
发送方:
-
由于超时后只能发送一个分组,现在的每个分组都拥有一个逻辑定时器(相较于GBN,所有的未确认分组共用一个定时器)
-
接收ACK,ACK序号在窗口内,将该序号分组标记为已接收。只有在刚好接收到与send_base相同的序号时,窗口才会向前移动(移动至下一个最小的未确认分组处),在移动之后,如果窗口中出现了未发生分组就会发送这些分组。
接收方:
如果接收到的分组的序号等于接收窗口的基序号,那么将该分组,以及该分组之后的已经缓存了的连续分组一同交付给上层。交付完成之后窗口会向前移动至已经交付了的分组编号之后。
接收方会重新确认已经受到过的那些序号小于当前窗口基序号的分组。也就是[rcv_base - N, rcv_base - 1]
内的分组会重新确认。假如rcv_base的ACK发送方没有收到,那么发送方会重新发送rcv_base分组,如果接收方不接受这个分组,那么发送方的窗口就将永远也无法向前移动,所以接收方需要能够重新确定已经收到过的分组。
有限序号范围:显示情况下序号总是有限的,如果发送方与接收方窗口之间缺乏同步会产生严重的后果。需要保证窗口大小最大为序号空间大小的一半。
比如:发送方发送次序是0 1 2 3 0 1 2 3…,发送方一次发送3个分组时,如果0 1 2都被接收方接收到了,并发回ACK0 1 2 ,但是ACK0没有被发送方接收到,此时发送方会重传分组0,而接收方由于接收到了基序号的分组已然向后移动了,但是向后移动的窗口可以接收到序号为3 0 1,包含了0,那此时接收方就无法区分接收到的0 到底是一个新的分组,还是重传的。如果窗口大小为序号空间的一半就可以避免这个问题。
这样假设发送方没有收到正确的ACK,窗口不移动,接收方接收到了分组,一直向后移动,最后的结果就是发送方的窗口占了一半序号,接收方的窗口占了一半的序号,接收方的窗口最大值刚好停在发送方的窗口最小值前面,而不会发生序号重复。
通过限定窗口大小可以解决上述问题,但是分组再发送方与接收方之间的信道中是存在被重新排序的可能的,所以还是会出现无法区分时新的分组还是重传的情况。通过为分组假定存活时间来解决,一个分组在网络中的存活时间不会超过某一个固定最大时间量。
计算信道利用率
信道利用率为:发送方实际忙于将发送方比特推进信道的那部分时间与发送时间之比。
RTT为传播时延,L为分组长度,R为链路传输速率
发送周期T = 传输时延 + 2*传播时延 + 确认分组的传输时延 (RTT + L/R + 确认分组的传输时延)
3.5 面向连接的运输:TCP
3.5.1 TCP连接
TCP面向连接(点对点),该连接是一条逻辑连接,两端的连接状态保存在两个通信系统的TCP程序中。
TCP连接建立过程:三次握手。客户首先发送一个特殊的 TCP 报文段,服务器用另一个特殊的 TCP 报文段来响应,最后,客户再用第三个特殊报文段作为响应。前两个报文段不承载 “有效载荷",也就是不包含应用层数据;而第三个报文段可以承载有效载荷。
发送数据时,会先将数据引导到该连接的发送缓存中,TCP会从发送缓存中取出数据,将数据放入报文段中进行封装,然后将数据传递到网络层。放入报文段中的数据数量受限于最大报文段长度(MSS)。MSS通常取决于最大链路层帧长度(MTU)。MSS值报文段中应用层数据的最大长度(不包括首部)。
3.5.2 TCP报文段结构
TCP报文段由首部字段和数据字段组成。MSS限制报文段数据字段的最大长度。当发送的文件较大时会将将其分解成长度为MSS的若干块(最后一块可能会小于MSS)
TCP报文段结构图:
- 源端口和目的端口:用于多路分解/复用
- 检验和字段
- 序号字段和确认号字段:TCP发送方使用和TCP接收方使用
- 接收窗口:用于流量控制,指示接收方愿意接收的字节数量
- 首部长度字段
- 选项字段
- 标志字段:ACK、RST、SYN、FIN、PSH、URG
- 紧急数据指针:紧急数据的最后一个字节由 16 比特的紧急数据指针字段( urgent data pointer field) 指出。当紧急数据存在并给出指向紧急数据尾指针的时候, TCP 必须通知接收端的上层实体 。
1、序号与确认号
TCP将数据看成一个无结构、有序的数据字节流,序号是建立在传送的字节流之上。报文的序号是该报文段首字节的字节流编号。
主机A填充进报文段的确认号是主机A期望从主机B收到的下一字节的序号。
发送报文段:
-
序号:当前报文段的数据的第一个字节的序号;
-
确认号:主机期望从另一个主机接收到的数据的序号
TCP值确认流中第一个丢失字节——累积确认,就是确认一次可以代表多个字节或者是报文。
由于报文段中需要填入数据,所以即使是最后一个报文段,没有发送数据,也要讲在序号中填入数据。
3.5.3 往返时间的估计与超时
TCP采用超时/重传机制来处理报文的丢失问题。
TCP实现超时/重传机制最明显的一个问题是超时间隔长度的设置。超时间隔必须大于RTT。
1、估计往返时间
RTT估计:
RTT变化的估计(RTT偏差):
反应了RTT的波动程度,当RTT波动程度较大时,这个偏差就大。
2、设置和管理重传超时间隔
超时间隔不能太小——引起不必要的重传,也不能太大——当报文段丢失时不能很快地实现重传。
超时处理:
3.5.4 可靠数据传输
TCP协议遵循单一重传定时器,即使有多个已发送但还未被确认的报文段。
1、TCP发送方
-
从上层应用程序接收数据
TCP从应用程序接收数据,将数据封装在一个报文段中,并把该报文段交给IP。
-
定时器超时
定时器与最早未被确认的报文段关联。
重传引起超时的报文段,TCP重启定时器。
比如:一次发送了多个报文段,(发送方知晓发送顺序),发送方会接收接收方发送的确认,如果有的报文确认在超时间隔内传回就不会重传该分组,如果有超时(有的报文确认没有在时间间隔内传回),那么就会重传当前还未确认的最早的分组,并重启定时器,如果在这个分组之后分组在新的超时间隔内传回了确认,那就不会再重传。
-
收到ACK
- 确认丢失重传
- 连续发送两个分组,由于前一个分组超时重传重启了定时器,使得第二个分组有充分的时间传输而没有超时重传
- 连续发送两个分组,前一个报文的ACK丢失,后一个报文的ACK在超时时间内到达,那么不会重传第一个报文段,因为是累积确认。
2、超时间隔加倍
超时之后计算的RTT显然是不准确的,因为可能发生了报文丢失。所以当出现超时时,直接将已有的超时间隔翻倍。
注:当定时器在接收到上层数据或ACK重启时,超时间隔由计算得到(之前的计算公式),而非直接翻倍,只有超时时的重启才会将其翻倍。
3、快速重传
超时重传存在的问题:超时的周期比较长,当一个报文段早早地丢失了,却只能等到发生了超时才能重传,使得时延增加。
解决方案:冗余ACK,发送方可以在超时时间发生之前通过注意到所谓的冗余ACK来检测丢包情况。
接收方接收到一个报文段,其序号大于所期望的报文段,说明数据流中出现了间隔,有报文段丢失,TCP会对已经接收到地最后一个按序字节数据进行重复确认即可。但是不同于GBN,TCP并不会丢弃失序报文段。
一旦接收到对相同数据的三个冗余ACK,TCP就会执行快速重传。
4、TCP与GBN和SR
(1) TCP累积确认(ACK)
TCP 确认是累积式的,正确接收但失序的报文段是不会被接收方逐个确认的,TCP发送方仅需维持已发送过但未被确认的字节的最小序号和下一个要发送字节的序号。
累积确认与GBN类似,但是TCP与GBN有一些显著差别,TCP会将正确接收但是失序的报文段可以进行缓存(取决于具体实现),而GBN会直接丢弃,所以这也导致GBN会进行大量的重传,而TCP不会。
(2) TCP选择确认(SACK)
TCP接收方有选择地确认失序报文段,而非累积地确认最后正确接受的最后一个连续分组。
如果有一个分组丢失了,那么需要三次冗余ACK才会进行重传,ACK只确认最后正确接收地一个连续分组,在这个丢失分组之后地分组即使正确到达了接收方,接收方也不会对其进行确认,只会继续发生冗余ACK(可以视为对正确接收地最后一个连续分组地确认),直至三个ACK之后,发送方重传了丢失分组,接收方接收到了,才会停止发送冗余ACK,而是发送接收到分组之后此时的最后正确接受的最后一个连续分组的序号。
对于SACK,如果有分组丢失,会有选择地确认分组,也就是不会像前者发送冗余ACK,而是发送之后到达的分组的ACK。SACK会将已经成功接收的多个数据段的序号范围这个信息放入,传回给发送方。发送方收到SACK报文后,可以知道哪些数据段已经成功接收,哪些数据段需要重传。
SACK准确的告知了发送方哪些数据已被成功接收,这样可以不用等待超时重传,也可以减少不必要的重传,减少网络拥塞与时延。
3.5.5 流量控制
TCP为应用程序提供了流量控制服务,这样可以消除发送方使接收方缓存溢出的可能性。
流量控制服务:是一个速度匹配服务,需要发送方的发送速率与接收方应用程序的读取速率相匹配。这样就可以消除发送方使接收方缓存溢出的可能性。
注:本节对TCP的假设可能与之前不同:TCP接收方丢弃失序的报文段。
发送方维护一个接收窗口进行流量控制,给发送方指示接收方还有多少多少可用的缓存空间。
上图为接收主机的接收窗口以及接收缓存,接收方会将接收窗口的大小发送给发送方,进而发送方可以根据窗口的大小来进行数据传输的控制。
发送方需保证:LastByteSent-LastByteAcked<=rwnd
,也就是发送且未确认的数据量需要控制在窗口大小内。
对于rwnd=0,若接收方给发送方发送窗口为0的数据,那发送方就会停止向接收方发送数据,而发送方不发送数据,接收方就不会发送数据,最终导致发送方被阻塞而不能再发送数据。→解决方案:发送方接收到接收窗口为0后,不会不向接收方发送数据,而是会发送一个只有一个字节数据的报文段,这样接收方就会给发送方传数据,并带来窗口大小。
3.5.6 TCP连接管理
1、三次握手
- 客户端→服务器,报文段不包含应用层数据,报文段首部一个标志位SYN为1,随机选择一个初始序号(client_isn)存入序号字段
- 服务器→客户端,SYN报文到达服务器,服务器为该TCP连接分配TCP缓存与变量。报文段不包含应用层数据,SYN为1,确认号字段为client_isn+1,随机选择初始序号server_isn存入序号字段
- 客户端→服务器,收到SYNACK报文段之后,客户要为连接分配缓存个变量。可以在报文段负载中携带客户到服务器的数据,SYN为0,确认号字段为server_isn+1,序号字段为client_isn+1
=> 能否使用“两报文握手”建立连接?
不可以。
2、四次挥手
参与一条TCP连接的两个进程中的任何一个都能终止连接。连接结束之后,主机中的缓存与变量都将被释放。
- 以客户进程发送关闭连接为例
- 客户端→服务器:客户TCP向服务器进程发送一个特殊的TCP报文段,FIN=1
- 服务器→客户端:服务器接收到报文,发送确认报文
- 服务器→客户端:终止报文段,FIN=1
- 客户端→服务器:客户端对服务器的终止报文段进行确认
3、客户端与服务器TCP的状态序列
上述讨论的是TCP都成功进行了连接的情况。对于端口号或者IP地址不匹配的情况:
-
TCP:服务器向客户端发送一个重置报文段,RST=1
-
UDP:服务器发送一个ICMP数据报
3.6 拥塞控制原理
1、拥塞的表现
- 分组丢失
- 分组经历较长的延时
2、拥塞的代价
-
代价1:假设路由器缓冲无限大(不会发生丢包),还是会存在一种拥塞代价,当分组的到达速率接近链路容量时,分组经历巨大的排队时延。
-
假定路由器缓冲容量有限(可能会发生丢包,丢包时进行分组重传)
- 假定发生端拥有路由器的全部信息,知道什么时候路由器的缓冲可用,那么就不会发生丢失,那么发送端发送的数据就不包含重传数据
- 假设发送端虽然没有路由器的全部信息,但是发送端知道分组是否发生了丢失,发生了丢失就重传分组
- 最现实的一种情况是,出现重复分组,也就是分组在链路中超时了,但是并没有丢失
代价2:发送方必须执行重传以补偿因为缓存溢出而丢失的分组
代价3:发送方在遇到大时延所进行的不必要的重传会引起路由器利用其链路带宽来转发不必要的分组副本
-
代价4:假定有多台路由器以及多跳路径,如果到达某一个路由器时,分组发生了丢失,那么关于这个分组的上游传输能力都被浪费了
3、拥塞控制方法
- 端到端拥塞控制
- 网络辅助拥塞控制
4、端到端拥塞控制方法——TCP
(1) 拥塞感知——超时机制,三次ACK
由于由于出错而被丢弃的可能性很小,所以大部分情况下超时都是因为发生了拥塞。
发生了三次ACK之后,说明有某个段丢失了,但是丢失的段之后的段收到了,说明发生了轻微拥塞。
(2) 速率控制方法
通过限制已发送但是还未确认的数据量——拥塞控制窗口cwnd
-
慢启动阶段
cwnd从1个MSS开始,每过一个RTT,发送速率就翻番。
-
当检测到了超时时,再次将cwnd设置为1,并重新开始慢启动,并设置一个慢启动阈值为上一次检测到了超时时的窗口大小的一半(
cwnd/2
)。(最开始其实并没有设置慢启动阈值,在发生了一次超时之后设置) -
当cwnd拥塞窗口的大小达到了慢启动阈值时,慢启动阶段结束,进入拥塞避免阶段。
-
当检测到了三个冗余的ACK时,执行快速重传,慢启动阈值减半,并进入快速恢复阶段。
-
-
拥塞避免阶段
此时cwnd的值为上次发生拥塞时的一半,在每个RTT将cwnd的值增加一个MSS。
- 出现超时时,将cwnd的值设置为1,同样也要设置一个慢启动阈值为上一次检测到了超时时的窗口大小的一半(
cwnd/2
),重新开始慢启动。 - 出现三个冗余ACK,执行快速重传,慢启动阈值减半,并进入快速恢复阶段
- 出现超时时,将cwnd的值设置为1,同样也要设置一个慢启动阈值为上一次检测到了超时时的窗口大小的一半(
-
快速恢复阶段
每收到一个冗余ACK时,cwnd增加一个MSS,如果收到了丢失报文段的ACK那么,将cwnd设置为慢启动阈值之后,进入拥塞避免阶段。