自顶向下计算机网络学习 传输层
- 一、概述和传输层服务
- 1.1 传输层提供的服务
- 1.2传输层和网络层的关系
- 1.3 传输层协议
- 可靠的、保序的传输:TCP
- 不可靠、不保序的传输:UDP
- 二、多路复用与解复用
- 2.1 什么是复用与解复用
- 2.2 面向连接(TCP)的多路复用与分解
- 2.3 无连接多路复用与分解
- 三、无连接传输:UDP
- 3.1 UDP报文段结构
- 3.2 UDP检验和
- 四、可靠数据传输的原理
- 4.1 rdt1.0: 在可靠信道上的可靠数据传输
- 4.2 rdt2.0:具有比特差错的信道
- 4.2.1 rdt2.1
- 4.2.2 rdt2.2:无NAK的协议
- 4.3 rdt3.0:具有比特差错和分组丢失的信道
- 4.4 流水线可靠数据传输协议
- 4.5 滑动窗口(slide window)协议
- 4.5.1 GBN
- 4.5.2 SR
- 4.5.3 对比GBN和SR
- 五、面向连接的传输:TCP
- 5.1 TCP概述
- 5.2 TCP报文段结构
- 5.3 TCP往返延时(RTT)和超时
- 5.4 TCP:可靠数据传输
- 5.4.1 TCP rdt 概述
- 5.4.2 TCP发送方
- 5.4.3 产生TCP ACK的建议
- 5.5 TCP快速重传
- 5.6 TCP流量控制
- 5.7 TCP连接管理
- 5.7.1 两次握手可行吗?
- 5.7.2 TCP3次握手
- 5.7 TCP:关闭连接
- 5.8 TCP状态描述(扩展)
- 5.8.1 客户TCP连接建立过程经历的状态
- 5.8.2 客户TCP连接释放过程经历的状态
- 六、拥塞控制原理
- 6.1 拥塞控制概述
- 6.2 拥塞的原因/代价
- 6.2.1 场景1:2个发送方和一台具有无穷大缓存的路由器
- 6.2.2 场景2:2个发送方和一台具有有限缓存的路由器
- 6.2.3 场景3:4个发送方和具有有限缓存的多台路由器及多跳路径
- 6.3.4 总结
- 七、TCP 拥塞控制
- 7.1 拥塞控制方法
- 7.2 ATM ABR拥塞控制
- 7.3 TCP拥塞控制机制
- 7.3.1 拥塞感知
- 7.3.2 速率控制方法
- 7.3.3 拥塞控制策略概述
- 7.3.4 总结
- 7.4 TCP 吞吐量
- 7.5 TCP公平性
一、概述和传输层服务
1.1 传输层提供的服务
传输层向上层提供的服务是进程和进程之间的以报文为单位的逻辑的通信。使不同进程的主机好像直接相连一样,如下图:
运输层协议是在端系统中实现的,而不是在路由器中实现的。
- 应用层通过SAP向传输层交付报文
- 传输层将报文划分成较小的报文段,每段都加上运输层首部以生成运输层报文段
- 在发送端系统中,将报文段交付给网络层
- 网络层将报文段封装成数据报发送给目的端
1.2传输层和网络层的关系
-
传输层提供了进程间的逻辑通信,网络层提供了主机之间的逻辑通信。
-
传输层的服务依赖于网络层的服务,还要加强网络层的服务为应用层提供更好的服务
服务加强的例子:
- IP提供的服务是不可靠的和不保序的,传输层的TCP协议在IP服务上提供了可靠的、保序的传输。
- 网络层提供的是主机与主机之间的逻辑通讯,传输层在网络层提供的服务之上,通过复用和解复用提供了进程之间的逻辑通讯。
.
注意,有些服务是不可以被加强的:带宽,延迟。
【UDP是去掉了握手的时间,提高了实时性; 而不是通过提升带宽来提升速度。】
这里举一个形象的例子:
在东海岸和西海岸有2个家庭,每个家庭里各有12个小孩,他们每周都会互相写信;每封信都会通过单独的信封通过邮局服务传送。
每个家庭都有一个管事的小孩,东海岸的是Ann,西海岸的是Bill。Ann负责收集他们家的信件,Bill也一样;Ann和Bill收集到信封后,就会将信封交给每天都会来到家门口的提供邮政服务的邮车上。
当邮车送信件到家门口时,也是Ann和Bill负责去统一拿信,再具体交付到自家小孩的手里。
再在上面的例子中:
- 主机=家庭
- 进程=小孩
- 应用层报文=信封中的信件
- 传输协议=Ann和Bill
- 网络层协议=邮政服务
可以看到Ann和Bill为家庭的小孩提供了复用解复用的服务;且Ann和Bill都是在家里进行工作的,所以运输层协议只运行在端系统,它只负责将应用层报文交付到网络边缘(来家门口的邮车)。
在邮寄过程中,邮车是不会对信封内容进行查看的;即中间路由器即不处理也不识别传输层加在应用层报文中的任何信息。
Ann和Bill提供的服务可能会存在差别,Ann比较勤快,会去查询信件的邮寄情况,当信件没有按时送到会使用信件副本再次邮寄【TCP】;而Bill比较懒,放到邮车上就行,是否送达到东海岸并不关心,所以邮件可能会出现丢失【UDP】。
1.3 传输层协议
可靠的、保序的传输:TCP
提供的服务:
- 多路复用、解复用
- 拥塞控制
- 流量控制
- 建立连接
不可靠、不保序的传输:UDP
- 多路复用、解复用
- 没有为尽力而为的IP服务添加更多的其它额外服务
TCP、UDP都不提供的服务:
- 延时保证
- 带宽保证
二、多路复用与解复用
2.1 什么是复用与解复用
一个进程有一个或多个套接字(socket),传输层相当于从网络向进程传递数据和从进程向网络传递数据的门户。
多路分解:
上图中间的主机的运输层将网络层收到的报文段分解后交给应用层的
P
1
P_1
P1或
P
2
P_2
P2进程;这一过程是通过将到达的报文段数据定向到对应进程的套接字完成的。
即Ann将收到的信件,按照信件上的信息(socket)分发给指定的小孩的过程。
多路复用:
从多个套接字接收来自多个进程的报文,根据套接字对应的IP地址和端口号等信息对报文段用头部加以封装
即Ann收集信件时,按照发信人的信息来填写信封信息的过程。
2.2 面向连接(TCP)的多路复用与分解
如上图,左边的应用进程通过SAP向传输层传递socket和message,TCP通过socket获取该message的源端口和目的端口,并封装成TCP报文段。
传输层将封装好的报文段传递给网络层,网络层通过socket获取该message的源IP和目的IP,并封装成IP数据报,通过网卡发送出去。
以上就是发送端的复用过程,根据上层传递的socket封装信息。
当右边的主机收到了IP数据报,根据数据报格式可以分解出源IP和目的IP,然后向上层传递;传输层同理分解出源端口和目的端口;这个四元组可以指向某一个socket,从而将数据发送给socket对应的PID(进程号)。
注意:
在分解时,只要四元组中的其中一个不同,都会指向不同的socket号。
.
如下图,中间的主机C向Web服务器B发起了两个HTTP会话,这两个会话源IP、目的IP、目的端口号都是一样的(都跑在服务器的80号端口上);但只因为源端口号不一样,则在Web服务器B多路分解时指向了不同的socket,所以Web服务器B能够正常的分解这个源IP、目的IP、目的端口号的连接。
.
2.3 无连接多路复用与分解
如上图,左边的应用进程通过SAP向传输层传递socket、message和&cad(指向目标IP和目标Port的指针),UDP通过socket和&cad获取该message的源端口和目的端口,并封装成UDP报文段。
传输层将封装好的报文段传递给网络层,网络层通过socket获取该message的源IP和目的IP,并封装成IP数据报,通过网卡发送出去。
以上就是发送端的复用过程,根据上层传递的socket和&cad封装信息。
当右边的主机收到了IP数据报,根据数据报格式可以分解出源IP和目的IP,然后向上层传递;传输层同理分解出源端口和目的端口;得到的二元组(目的IP和目的Port)可以指向某一个socket,从而将数据发送给socket对应的PID(进程号)。
TCP是四元组,一个sock只能使服务器与一个客户端连接。但UDP是二元组,一个服务器的sock可以同时与多个客户端进行交互。
.
如上面举的Web服务器B的例子,若传输层使用的是UDP协议,那么对于目的IP和目的Port相同的主机A和主机C的请求,都会被同一个进程所响应。
三、无连接传输:UDP
UDP在IP之上仅添加了复用/分用功能及少量的差错检验。
所以应用程序使用的是UDP协议,则该程序差不多是直接与IP打交道;而IP提供的是“尽力而为”的服务,所以UDP提供的也是“尽量而为”的服务。
-
UDP提供的是==“尽力而为”==的服务,所以报文段可能:
(1) 丢失;
(2)送到应用进程的报文段乱序。 -
UDP是无连接的:
(1)发送报文段之前,UDP发送端和接收端之间没有握手;
(2)每个UDP报文段都被独立地处理 -
UDP 被用于:
(1)流媒体(丢失不敏感,速率敏感、应用可控制传输速率);
(2)DNS;
如果希望运用udp的高效率,又希望它可靠。那只能在应用层层面上去解决可靠性问题。
.
如:QUIC,一种基于UDP的低时延的互联网传输层协议。QUIC基于UDP传输数据,在应用层面解决可靠性问题,同时又能享受UDP协议的低时延优点。
- UDP没有拥塞控制,所以想发多少数据就发多少数据;应用层下发数据的速度和网络层发送数据的速度相一致,适合用于实时多媒体技术
3.1 UDP报文段结构
3.2 UDP检验和
源端做校验和的计算,目的端做校验和判断,判断UDP报文段从源端到达目的端的移动时,其中的比特是否发生了改变,改变了则丢弃。
检验流程:
- 发送端将报文段按16比特进行划分,不足的以0补充。
- 将16比特字进行两两相加,并采取进位回卷。【进位回卷:进位的1加到最低位上去】
- 最后将计算的和取反码,将结果放置到检验和位置
- 在发送端,将收到的报文段按16比特划分并相加。
- 若结果为全1,则代表传输过程无差错
注意:
结果为0表示传输过程中必然出现了差错,结果为全1不能表示过程中一定没出现差错,只能表示大概率没出错。
四、可靠数据传输的原理
可靠数据传输(rdt)在应用层、传输层和数据链路层都很重要。
rdt的任务:
在下层提供的服务是不可靠的情况下,本层的协议机制/实体要靠哪些时空资源的安排、要靠哪些机制的安排,向上层提供可靠的服务。
下图是本小节学习可靠性传输的整体框架
等待上层原语的调用,rdt规定本层的协议动作确保可靠性传递数据,然后对下层的服务进行数据的发送
发送端:
上层通过调用rdt_send(),将数据向下层传递,本层协议通过一系列操作后(确保可靠性的操作),将数据打包成packet,通过调用函数udt_send()使用下层提供的服务发送给接收端。【udt表示不可靠数据传输】
接收端:
分组从信道到达接收端时,rdt协议将调用rdt_rcv()接收发过来的packet,通过一系列确保可靠性服务的操作后,调用dliver_data()将数据向高层交付。
我们将下层的服务抽象成一个信道,在使用信道服务的基础上实现rdt协议。下面将讨论在不同信道请情况下,rdt协议的实现方式。
4.1 rdt1.0: 在可靠信道上的可靠数据传输
- 假设下层的信道是完全可靠的:
(1)没有比特出错;(2)没有分组丢失。
发送方:
调用rdt_send()触发rdt_send(data)事件,通过make_pkt(data)动作产生一个包含数据的分组,并通过udt_send(packet)动作将分组发送到信道上。
接收端:
通过rdt_rcv(data)事件从底层信道接收一个分组,通过extract (packet,data)动作从分组中取出数据,并通过deliver_data(data)动作上交给高层。
因为信道是可靠的,所以rdt协议只需要在使用下层可靠的服务基础上实现数据的分组封装和解封装。
4.2 rdt2.0:具有比特差错的信道
- 假设下层信道可能会出错:将分组中的比特翻转。(则需要用校验和来检测比特差错)
问题:怎样从差错中恢复。
举个例子:
打电话,当对方听清了你说的话,会回复你一个“OK”,表示正确接收了;当对方没有听清你说的话,会回复你“不OK”,要求你在重说一次;
在计算机网络中,上述的过程可被称为自动重传请求协议(ARQ):
- ACK(确认):上述的"OK",接收方显式地告诉发送方分组已被正确接收;
- NAK(否定确认):上述的"不OK",接收方显式地告诉发送方分组发生了差错;
- 发送方收到NAK后,发送方重传分组
rdt2.0协议的FSM描述如下:
发送方:
调用rdt_send()触发rdt_send(data)事件,通过make_pkt(data)动作产生一个包含数据的分组,并通过udt_send(packet)动作将分组发送到信道上。
接下来发送方协议等待来自接收方的ACK或NAK分组。
若收到NAK分组触发rdt_rcv(rcvpkt)&&isNAK(rcvpkt)事件,并调用udt_send(sndpkt)将分组重传;
若收到ACK分组触发rdt_rcv(rcvpkt)&& isACK(rcvpkt)事件,回到初始状态等待上层的调用。
接收方:
通过rdt_rcv(data)事件从底层信道接收一个分组,通过校验和判断分组中的比特是否发生翻转。
若发生翻转,则触发rdt_rcv(rcvpkt)&&corrupt(rcvpkt)事件,采取udt_send(NAK)动作,向发送方发送NAK分组。
若没发生翻转,则触发rdt_rcv(rcvpkt)&¬corrupt(rcvpkt)事件,采取extract (packet,data)动作从分组中取出数据,然后通过deliver_data(data)动作上交给高层,并向发送方发送ACK分组【udt_send(ACK)】。
rdt2.0协议发送完一个数据,等待回复后才会发送下一个数据;这样的协议被称为停等(stop-and-wait)协议
4.2.1 rdt2.1
rdt2.0的致命缺陷:没有考虑到ACK或NAK分组受损的可能性。
考虑处理受损ACK和NAK的三种可能性:
- 第一种可能:当收到受损的ACK或NAK,发送方不知该作何处理。
- 第二种可能:增加足够的检验和bit,使得发送方不仅可以检测差错,还可以恢复差错。
- 第三种可能:当收到受损的ACK或NAK,只需重传当前分组。
对于第三种可能,它向接收方的信道中引入了冗余分组;这会使接收方在收到冗余分组时,不能判断接收到的分组是新的分组还是旧分组的重传。
为了解决上面的问题,在数据分组中添加序列号,两个序列号(0,1)就足够了。【足够表示新旧分组,所以rdt2.1相比rdt2.0添加了序号。】
因为假设下层信道是不会丢失分组的,所以对于ACK\NAK不需要指明它们需要确认的分组序号。发送方会知道ACK\NAK是响应最近发送的分组的。
rdt2.1的运行图:
rdt 2.1协议的FSM描述如下:
发送方:
初始状态是序号为0的状态,当发送序号为0的的数据分组后,发送方会处于序号0的状态并等待ACK/NAK的到来,即上图右上角的状态。当发送方收到受损的ACK/NAK,会再次序号0数据分组,并继续处于序号0的状态,等待ACK/NAK的到来。
当收到了正确的ACK/NAK,发送方就会进入序号为1的状态并等待上层向接收方发送序号1数据分组的调用。状态为序号1和状态为序号0的发送过程一致。
接收方:
初始状态为序号0,等待序号0的数据分组的到来;
当收到数据,检验后未出错,并且序号为0,则向高层提交数据并向发送方发送ACK。然后状态转到序号1;
当收到数据且检验后出错,则向发送方发送NAK,并继续处于序号0状态。
当收到数据,检验后未出错,但是序号为1,则表示接收方收到了旧的分组,则向发送方发送ACK,让发送方发送新的序号为0的分组。
状态为1时与上述类似。
rdt2.1的运行图:
4.2.2 rdt2.2:无NAK的协议
rdt2.2功能同rdt2.1,但只使用ACK(ack 要编号)。接收方对最后正确接收的分组发ACK,以替代NAK,如下图:
例如:
当发送方已经发送了序号为1的分组,且收到ACK0;则表示接收方最近正确接收的分组序号为0,序号为1的分组可能发生了损坏,发送方需要重传序号为1的分组;因此ACK0代替了NAK1。
rdt2.2运行图:
4.3 rdt3.0:具有比特差错和分组丢失的信道
- 假设下层信道可能会比特受损和丢失分组(数据或ACK)
rdt2.2已经通过序号、检验和、ACK分组和重传解决了信道比特受损的问题。
但以上措施不足与解决下层信道丢失分组的问题;
如当发送方发送了一个数据分组,接收方接收并返回一个ACK,但ACK在传输过程中出现了丢失,那么发送方就会持续等待这个ACK,而接收方会持续等待发送方的下一个分组,从而造成了死锁。
所以rdt3.0在rdt 2.2的基础上引入了超时重传机制:发送方等待ACK一段合理的时间(需要一个倒计数定时器,发送后开始计时),如果到时没有收到ACK,发送端超时重传数据分组。
也许ACK并没有丢失,只是被延迟了。超时重传将会导致数据重复,但利用序列号已经可以处理这个问题。
rdt 3.0协议的FSM描述如下:
- 橙框部分:发送方发送数据分组后,开始启动计时器
- 篮筐部分:当接收到正确的ACK反馈,关闭计时器
- 红框部分:当计时器到时还未收到ACK,则重新发送数据分组
rdt3.0的运行图:
当超时计时器设置的时间过短时:
过早超时(延迟的ACK)也能够正常工作;但是效率较低,一半的分组和ACK是重复的;所以设置一个合理的超时时间也是比较重要的;
4.4 流水线可靠数据传输协议
rdt 3.0性能问题的核心在于它是个停等协议。
假设有台端系统正在通信,两个端系统之间的往返传播时延RTT为30毫秒。彼此通过一条发送速率R为1Gbps的信道相连。现发送一条分组长度L为1000字节(8000比特)的数据分组,假设ACK分组很小,可以忽略发送时间。
则发送方的信道利用率为:
U
s
e
n
d
e
r
=
将
比
特
送
进
信
道
的
时
间
发
送
时
间
=
L
/
R
R
T
T
+
L
/
R
U_{sender}=\frac{将比特送进信道的时间}{发送时间}=\frac{L/R}{RTT+L/R}
Usender=发送时间将比特送进信道的时间=RTT+L/RL/R
图例如下图所示:
可以看到信道利用率非常的低
rdt 3.0在可靠性上已经达到了要求,但是在效率上很难满足现在的需求。
rdt 3.0 好比在一条很长的高速公路上运输货物,因为是停等协议,所以一次性只能发一辆货车,这条马路在很长一段时间内只有一辆车在跑;而且还要等目的端的卡车跑回来说已经送达了才能发出下一辆,从而导致高斯公里的利用率很低。
.
所以为什么不一次性发几辆车呢?这就是后面的流水线协议。
所以解决rdt 3.0的方法是:不以停等方式运行,允许发送方发送多个分组而无需等待确认。
发送方一次性向接收方发送的多个分组可以看成是多个分组填充到了一条水流中去,故该技术被称为流水线技术。
如下图,在等待确认之前发送3个报文,其利用率也基本上提高3倍。
实现流水线技术需要在原本的可靠数据传输协议之上实现:
- 增加序号范围:每个未被确认的分组必须有唯一的序号
- 协议双方需要缓存多个分组
- 当出现比特翻转和分组丢失时有两种策略:
(1)回退N步(GBN);(2)选择重传(SR)。
4.5 滑动窗口(slide window)协议
- 发送缓冲区:
- 发送窗口:
发送缓冲区内容的一个范围,那些已发送但是未经确认分组的序号构成的空间。
【发送窗口的最大值<=发送缓冲区的值】
发送窗口与发送缓冲区的关系如下图:
【发送窗口是发送缓冲区的一个子集】
绿色部分表示缓冲区,存放着要发送给接收方的数据。
发送窗口由窗口前沿和后沿,前沿和后沿圈出得蓝色部分即发送窗口,表示0号数据分组已经发送但未收到确认。
即发送窗口是指已发送但未收到确认的分组。
而落在绿色的发送缓冲区的1~4号数据分组可以发送给接收方。
发送窗口的移动:
- 前沿的移动:
每发送一个分组,前沿前移一个单位
如下图,发送0号分组前:
如下图,发送0号分组后,前沿前移
- 后沿移动:
收到老分组的确认,后沿的移动不能够超过前沿
如下图,收到已发送的0号分组的ACK前:
如下图,收到已发送的0号分组的ACK后:
因为0号分组是缓冲区的“前沿”,所以缓冲区窗口整体向前移
- 接收窗口=接收缓冲区:
接收窗口用于控制哪些分组可以接收
当接收窗口尺寸Wr=1,则只能顺序接收
当接收窗口尺寸Wr>1 ,则可以乱序接收
- 发送窗口=1,接收窗口=1 → → →停等协议
- 发送窗口>1,接收窗口=1 → → →GBN
- 发送窗口>1,接收窗口>1 → → →SR
4.5.1 GBN
G B N GBN GBN发送窗口 > 1 >1 >1,接收窗口 = 1 =1 =1。
因为接收窗口=1,所以当收到分组后就直接交付给上一层。所以不允许乱序接收,只能按序接收。
正常情况下 G B N GBN GBN的2个窗口互动:
- 发送方有新的分组落入发送缓存区范围,将分组发送出去,发送窗口前沿滑动;
- 接收方收到分组,分组序号落入到接收范围内(即按序到达),则接收,且向发送方发送确认。
- 发送方收到老的低序号分组的确认,后沿向前滑动,新的分组可以落入发送缓冲区的范围。接收方采用累加确认的方式;
异常情况下 G B N GBN GBN的2个窗口互动:
- 发送方有新的分组落入发送缓冲区范围,,将分组发送出去,发送窗口前沿移动;
- 接收方收到乱序分组,没有落入到接收窗口范围内,抛弃分组。并且重复发送老分组的确认。
- 发送方来了老分组的重复确认,发送窗口后沿不向前滑动,新的分组也无法落入发送缓冲区的范围;
- 若发送方超时机制触发,发送方将发送窗口中的所有分支发送出去。即发送所有已发送但未收到确认的分组。
G
B
N
GBN
GBN发送方的
F
S
M
FSM
FSM:
-
① \color{red}{①} ①、初始状态,窗口后沿 b a s e = 1 base=1 base=1,窗口前沿 n e x t s e q n u m = 1 nextseqnum=1 nextseqnum=1, b a s e = = n e x t s e q n u m base==nextseqnum base==nextseqnum即当前窗口大小为0。
【在真实情况中,发送窗口的序号是双方约定的,不一定从1开始】 -
② \color{red}{②} ②、
- r d t _ s e n d ( d a t a ) rdt\_send(data) rdt_send(data):表示上层有需要交付的数据;
- ( n e x t s e q n u m < b a s e + N ) (nextseqnum < base+N) (nextseqnum<base+N):若发送窗口前沿 n e x t s e q n u m nextseqnum nextseqnum没有超过发送缓冲区 b a s e + N base+N base+N,即发送缓冲区还有未发送的数据;
- s n d p k t [ n e x t s e q n u m ] = m a k e _ p k t ( n e x t s e q n u m , d a t a , c h k s u m ) sndpkt[nextseqnum] = make\_pkt(nextseqnum,data,chksum) sndpkt[nextseqnum]=make_pkt(nextseqnum,data,chksum):将发送窗口前沿指向的数据打包成数据分组;
- u d t _ s e n d ( s n d p k t [ n e x t s e q n u m ] ) udt\_send(sndpkt[nextseqnum]) udt_send(sndpkt[nextseqnum]):使用将数据交付给下层,发送给接收方;
- i f ( b a s e = = n e x t s e q n u m ) if (base == nextseqnum) if(base==nextseqnum):若当前发送的是第一个数据,启动超时计时器。【注意:后面发送的多个数据分组共享第一个发送数据分组的超时计时器】
-
③ \color{red}{③} ③、
- t i m e o u t timeout timeout:超时计时器到时
- s t a r t _ t i m e r start\_timer start_timer:重新启动超时计时器
- u d t _ s e n d ( s n d p k t [ b a s e ] s n d p k t [ n e x t s e q n u m − 1 ] ) ) udt\_send(sndpkt[base]~sndpkt[nextseqnum-1])) udt_send(sndpkt[base] sndpkt[nextseqnum−1])):重传所有未收到确认的分组(发送窗口内的分组)
-
④ \color{red}{④} ④、
- r d t _ r c v ( r c v p k t ) & & n o t c o r r u p t ( r c v p k t ) rdt\_rcv(rcvpkt)\&\¬corrupt(rcvpkt) rdt_rcv(rcvpkt)&¬corrupt(rcvpkt):收到接收方发送的确认并且确认并没出错,采取以下行动
- b a s e = g e t a c k n u m ( r c v p k t ) + 1 base = getacknum(rcvpkt)+1 base=getacknum(rcvpkt)+1:累计确认,窗口后沿滑动
- I f ( b a s e = = n e x t s e q n u m ) If (base == nextseqnum) If(base==nextseqnum):若后沿到达前沿,即所有分组都发送完,停止计时器;否则重启计时器。
-
⑤ \color{red}{⑤} ⑤、
- r d t _ r c v ( r c v p k t ) & & c o r r u p t ( r c v p k t ) rdt\_rcv(rcvpkt) \&\&corrupt(rcvpkt) rdt_rcv(rcvpkt)&&corrupt(rcvpkt):收到错误的确认信息,丢弃。
G
B
N
GBN
GBN接收方的
F
S
M
FSM
FSM:
-
① \color{red}{①} ①、
- e x p e c t e d s e q n u m = 1 expectedseqnum=1 expectedseqnum=1:当前接收窗口序号为1
-
③ \color{red}{③} ③、
-
r
d
t
_
r
c
v
(
r
c
v
p
k
t
)
&
&
n
o
t
c
u
r
r
u
p
t
(
r
c
v
p
k
t
)
&
&
h
a
s
s
e
q
n
u
m
(
r
c
v
p
k
t
,
e
x
p
e
c
t
e
d
s
e
q
n
u
m
)
:
rdt\_rcv(rcvpkt)\&\¬currupt(rcvpkt)\&\&hasseqnum(rcvpkt,expectedseqnum):
rdt_rcv(rcvpkt)&¬currupt(rcvpkt)&&hasseqnum(rcvpkt,expectedseqnum):
接收方收到分组,未出错,且按序接收;则采取以下动作; - e x t r a c t ( r c v p k t , d a t a ) extract(rcvpkt,data) extract(rcvpkt,data):解封装
- d e l i v e r _ d a t a ( d a t a ) deliver\_data(data) deliver_data(data):向上层交付数据
- s n d p k t = m a k e _ p k t ( e x p e c t e d s e q n u m , A C K , c h k s u m ) sndpkt=make\_pkt(expectedseqnum,ACK,chksum) sndpkt=make_pkt(expectedseqnum,ACK,chksum):计算校验和,组合 A C K ACK ACK后向发送方发送确认
- u d t _ s e n d ( s n d p k t ) : udt\_send(sndpkt): udt_send(sndpkt):发送 A C K ACK ACK
- e x p e c t e d s e q n u m + + expectedseqnum++ expectedseqnum++:接收窗口后移
-
r
d
t
_
r
c
v
(
r
c
v
p
k
t
)
&
&
n
o
t
c
u
r
r
u
p
t
(
r
c
v
p
k
t
)
&
&
h
a
s
s
e
q
n
u
m
(
r
c
v
p
k
t
,
e
x
p
e
c
t
e
d
s
e
q
n
u
m
)
:
rdt\_rcv(rcvpkt)\&\¬currupt(rcvpkt)\&\&hasseqnum(rcvpkt,expectedseqnum):
rdt_rcv(rcvpkt)&¬currupt(rcvpkt)&&hasseqnum(rcvpkt,expectedseqnum):
4.5.2 SR
正常情况下 S R SR SR的2个窗口互动:
- 发送方有新的分组落入发送缓存区范围,将分组发送出去,发送窗口前沿滑动;
- 接收方收到分组,分组序号落入到接收范围内,则接收,且向发送方发送确认; S R SR SR采用逐一确认,即一个 A C K ACK ACK确认一个分租;
- 发送方收到老的低序号分组的确认,后沿向前滑动,新的分组可以落入发送缓冲区的范围。
异常情况下 S R SR SR的2个窗口互动:
- 接收方新的分组落入发送缓冲范围,发送窗口前沿滑动;
- 接收方收到乱序的分组,落入在接收窗口范围内,接收;且发送该分组的确认,采取单个分组单独确认;
- 接收方收到了乱序分组的确认,发送窗口后沿不向前滑动,新的分组无法落入发送缓存区范围。
- 若接收方超时重发机制触发,将超时的分组重传发送出去。
选择重传SR的运行:
4.5.3 对比GBN和SR
- 相同之处:
- 发送窗口>1
- 一次能够可发送多个未经确认的分组。(都是流水线协议)
- 不同之处:
- GBN :接收窗口尺寸=1
- 接收端:只能顺序接收
- 发送端:一旦一个分组没有发成功,重传发送窗口全部分组
- 多个分组公用一个超时计时器
- 采用累计确认
- SR: 接收窗口尺寸>1
- 接收端:可以乱序接收
- 发送端:选择重传
- 每个分组单独一个超时计时器
- 采用单独确认
- GBN :接收窗口尺寸=1
五、面向连接的传输:TCP
5.1 TCP概述
-
点对点:
一个发送方,一个接收方 -
提供可靠的、按顺序的字节流服务
- 没有报文边界
没有报文边界的理解:
- 对于UDP:
发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。因此,应用程序必须选择合适大小的报文。- 对于TCP:
TCP不像UDP一样那样一个个报文独立地传输,而是在不保留报文边界的情况下以字节流方式进行传输。
TCP头部占20字节,以太网最大传输单元(MTU)为1500字节,所以TCP对上层交付的报文拆解成最大报文长度(MSS)为1480字节的报文。
-
流水线协议
-
具有发送和接收缓存
-
全双工通信
在同一连接中数据流双向流动 -
面向连接
在数据交换之前,通过握手(交换控制报文)初始化发送方、接收方的状态变量 -
有流量控制
发送方不会淹没接收方
5.2 TCP报文段结构
- 序号:报文段首字节的在字节流的编号。
- 确认号:表示对数据的确认,采用累计确认。
如确认号为 116 116 116表示 116 116 116字节之前的数据我都收到了,请从 116 116 116字节开始给我传送字节流数据。
TCP对于接收方如何处理乱序的报文段没有规定:
丢弃或者保存都可以
- ACK: A C K = 1 ACK=1 ACK=1时,确认号字段才有效。
- 接收窗口:愿意接收字节的数量,用于调节收发之间的速度。
- SYN: T C P TCP TCP连接建立过程为1
- FIN: T C P TCP TCP链接释放过程为1
5.3 TCP往返延时(RTT)和超时
在大型网络中,传播时间是很分散的,如下图:
-
将 R T T RTT RTT设置在红色的位置, R T T RTT RTT太短,会导致太早超时,引起不必要的重传。
-
将 R T T RTT RTT设置在蓝色的位置, R T T RTT RTT太长,会导致对报文段丢失反应太慢,消极。
那么如何估计 R T T RTT RTT呢?
-
可以进行采样,发出一条报文段,然后测量从报文段发出到收到确认的时间,作为 S a m p l e R T T SampleRTT SampleRTT(如果有重传,忽略此次测量)。
但由于路由器的拥塞和端系统负载的变化,这些报文段的 S a m p l e R T T SampleRTT SampleRTT会随之波动。所以,任何 S a m p l e R T T SampleRTT SampleRTT的值都是非典型的;因此,为了获取一个典型的 R T T RTT RTT,这里采用加权求和的方式来得到平滑的 R T T RTT RTT预估值:
E s t i m a t e d R T T = ( 1 − α ) ∗ E s t i m a t e d R T T + α ∗ S a m p l e R T T EstimatedRTT = (1- α)*EstimatedRTT + α*SampleRTT EstimatedRTT=(1−α)∗EstimatedRTT+α∗SampleRTT
-
除了估算 R T T RTT RTT外,测量 R T T RTT RTT的变化也是有价值的。这里定义了 R T T RTT RTT偏差 D e v R T T DevRTT DevRTT,用于估算 S a m p l e R T T SampleRTT SampleRTT偏离 E s t i m a t e d R T T EstimatedRTT EstimatedRTT的程度:
D e v R T T = ( 1 − β ) ∗ D e v R T T + β ∗ ∣ S a m p l e R T T − E s t i m a t e d R T T ∣ DevRTT = (1-β)*DevRTT +β*|SampleRTT-EstimatedRTT| DevRTT=(1−β)∗DevRTT+β∗∣SampleRTT−EstimatedRTT∣ -
D e v R T T DevRTT DevRTT代表当前网络的波动程度;当 D e v R T T DevRTT DevRTT较大时,应该设置较大的安全边界时间,即将 R T T RTT RTT预估值调大,以适应波动。所以最后的超时时间间隔设置为:
T i m e o u t I n t e r v a l = E s t i m a t e d R T T + 4 ∗ D e v R T T TimeoutInterval = EstimatedRTT + 4*DevRTT TimeoutInterval=EstimatedRTT+4∗DevRTT
可以理解前面的加权平均得到的 E s t i m a t e d R T T EstimatedRTT EstimatedRTT表示为均值, D e v R T T DevRTT DevRTT看作方差。假设大型网络中的往返时长符合正态分布,那么将值设置为[均值+4*方差]可以满足99%以上的设备之间的往返时长。
5.4 TCP:可靠数据传输
T C P TCP TCP是在 I P IP IP不可靠的尽力而为上创建了一种可靠数据传输服务。
-
T
C
P
TCP
TCP提供可靠数据传输的方法涉及已经再前面提到过:
- A C K ACK ACK分组和重传
- 序号
- 检验和
- 超时重传
- 在可靠传输的基础上提高效率,
T
C
P
TCP
TCP采用的是流水线技术;之前学习到的流水线协议有:
- GBN
- SR
但 T C P TCP TCP与 G B N GBN GBN和 S R SR SR都存在不同,可以看作 G B N GBN GBN和 S R SR SR的组合。
5.4.1 TCP rdt 概述
T C P TCP TCP:
- 采用了累计确认(像 G B N GBN GBN)
- 单个重传定时器(像 G B N GBN GBN)
- 对于是否可以乱序接收,没有规范
- 通过以下时间触发重传:
- 计时器超时,只重发最早未确认的报文段(像 S R SR SR)
- 重复的确认
5.4.2 TCP发送方
下图是忽略重复的确认、流量控制和拥塞控制得到的简化版的 T C P F S M TCP\ FSM TCP FSM:
-
① \color{red}{①} ①、
初始状态,发送窗口前沿和后沿等于发送双方约定的一个初始序号; -
② \color{red}{②} ②、
从上层应用层程序接收到数据,并生成具有序号 N e x t S e q N u m NextSeqNum NextSeqNum的报文段,然后将报文段交付给 I P IP IP层;
发送窗口前沿移动 l e n g t h ( d a t a ) length(data) length(data)个字节;
若此时计时器没有运行,启动计时器; -
③ \color{red}{③} ③、
若发生了 t i m e o u t timeout timeout(定时器超时),重传具有最小序号但任未答应的报文段,并重新启动计时器; -
④ \color{red}{④} ④、
若收到 A C K ACK ACK,且具有 A C K ACK ACK字段值 y y y;
当 y y y大于发送窗口后沿,因为是累计确认,所以将窗口后沿移动到 y y y;
若此时没有任何应答报文段,启动定时器。
5.4.3 产生TCP ACK的建议
【下述例子种,蓝色代表已到达;白色代表还未收到】
-
第一种情况:按序到达;
如下图,当报文段 1 1 1按序到达, 0 0 0以及以前的报文段都已经发送了 A C K ACK ACK;
此时接收方最多停留500 m s ms ms等待序号 2 2 2报文段的到达;若时间间隔内未到,发送 A C K 2 ACK2 ACK2,表示2之前的都收到了,希望下一个发送序号为2的报文段;
-
第二种情况:
报文段按序到达,在500 m s ms ms内下一个报文段也按序到达,立即发送单个累计 A C K ACK ACK,即 A C K 3 ACK3 ACK3,表示3号之前的报文段我都收到了,希望下一个发送序号为3的报文段。
-
第三种情况:乱序到达;
立即发送 A C K 2 ACK2 ACK2,指明下一个期待的报文段序号是2;
-
第四种情况:
若第三种情况中间的2报文段到达了,填充了间隔的低端,则立即发送 A C K 4 ACK4 ACK4。
5.5 TCP快速重传
超时触发重传存在的问题之一是超时周期可能会相对比较长。当报文段出现了对丢失,这种长超时周期会增加端到端的时延。
幸运的是,发送方可以通过冗余ACK来提前检测到丢包情况。
冗余 A C K ACK ACK即再次确认某个报文段的 A C K ACK ACK;根据上一小节,当出现情况3时,即出现中间间隔时会发送冗余的 A C K ACK ACK;
这个间隔可能是由于在网络中报文段丢失或者重新排序造成的。因此冗余的 A C K ACK ACK可以看作报文段丢失的一个信号。
如果发送方收到同一数据的 3 \color{red}{3} 3个冗余 A C K ACK ACK,就会立即重传最小序号的段,不用等待定时器过时。
注意:
- T C P TCP TCP采用的是累计确认,所以3次冗余ACK都是对同一个报文段的确认。
- 总的来说,发送方收到了 4 4 4次(第1次正常的确认和后面3次冗余的确认)相同报文段的 A C K ACK ACK确认才会启动快速重传。
5.6 TCP流量控制
流量控制:
接收方控制发送方,不让发送方发送的太多、太快以至于让接收方的缓冲区溢出。
- 接收方在其向发送方的 T C P TCP TCP段头部的 r w n d rwnd rwnd(接收窗口)字段“通告”其空闲 b u f f e r buffer buffer(缓存)大小。
- 发送方会限制发送窗口的大小≤接收方发送过来的 r w n d rwnd rwnd值,以保证接收方不会被淹没
5.7 TCP连接管理
5.7.1 两次握手可行吗?
T C P TCP TCP双方在正式交换数据之前,发送方和接收方握手建立通信关系:
- 同意建立连接(每一方都知道对方愿意建立连接)
- 同意连接参数
采用 2 2 2次握手建立连接可行吗?
先来看看正常的 2 2 2次握手建立连接:
类似小明和小红要进行聊天,彼此之间不知道对方是否想要进行聊天;小红先向小明发出询问:“让我们一起聊天吧”,小明收到小红的询问后向小红回话:“好的”。此次小红和小明之间的双向连接就建立了起来。如下图:
但是上面的情况是基于下层可靠的信道(不丢失、不乱序)下进行的。
下面我们基于现实中的信道讨论2次握手的失败场景:
-
场景1:半连接(只在服务器端维护了连接!)
客户端向服务器端发出 T C P TCP TCP连接请求 r e q _ c o n n ( x ) req\_conn(x) req_conn(x),服务器端收到请求后同意连接并响应请求 a c c _ c o n n ( x ) acc\_conn(x) acc_conn(x);
一段时间后,客户端还没收到服务器的响应,重新发送连接请求 r e q _ c o n n ( x ) req\_conn(x) req_conn(x);过了一段时间客户端第一次请求的响应请求到达客户端,连接建立。
数据传输完毕后,双方中段连接。但之前重发的连接请求 r e q _ c o n n ( x ) req\_conn(x) req_conn(x)到达了服务器端,服务器端会维护这一段连接的状态并响应;客户端收到响应之后会丢弃,但服务器并不知道,所以在服务器端维护了虚假的半连接。
-
场景2:老的数据被当成新的数据接受了
在场景1的基础上,在连接是否之前重传了一次 d a t a ( x + 1 ) data(x+1) data(x+1)数据;
在重传的数据 d a t a ( x + 1 ) data(x+1) data(x+1)和重传的连接请求 r e q _ c o n n ( x ) req\_conn(x) req_conn(x)到达服务器之前,双方就已经中断了连接,但是重传的请求到达服务器端之后,服务器建立了虚假的半连接;重传的旧数据 d a t a ( x + 1 ) data(x+1) data(x+1)到达了服务器端,就会被服务器当成新的数据接收了。(但 d a t a ( x + 1 ) data(x+1) data(x+1)是残留在网络上的无用数据)。
注意:
因为 2 2 2次连接双方彼此不能约定参数,所以发送的数据序号都从一个固定值开始。从而加大旧数据被当成新数据接收的概率。
所以,2次连接会造成:
- 会维护没有必要的半连接
- 接收无用的数据占用缓存
5.7.2 TCP3次握手
下面来看一看 T C P 3 TCP\ 3 TCP 3次握手:
- 第一步:
客户端的 T C P TCP TCP首先向服务器端的 T C P TCP TCP发送一个特殊的 T C P TCP TCP报文。该报文段中不包含应用层数据。
该报文段的首部的 S Y N SYN SYN标志位会被置为1,因此该报文段可被称为 S Y N SYN SYN报文段。
此外,客户端会随机地选择一个初始序号 c l i e n t _ i s n client\_isn client_isn,并将序号置于报文段的序号字段中。 - 第二步:
服务器收到 T C P S Y N TCP\ SYN TCP SYN报文段的 I P IP IP数据报,服务器会从中提取出 T C P S Y N TCP\ SYN TCP SYN报文段,并为该 T C P TCP TCP连接分配 T C P TCP TCP缓存和变量,并向客户端 T C P TCP TCP发送允许连接的报文段( S Y N A C K SYNACK SYNACK报文段)。
该允许连接的报文段也不包含应用层数据,但在报文段首部包含3个重要的信息:- S Y N SYN SYN比特被置为1
- 首部的确认号字段被置为 c l i e n t _ i s n + 1 client\_isn+1 client_isn+1
- 服务器选择自己的初始序号 s e r v e r _ i s n server\_isn server_isn
- 第3步:
客户端收到 S Y N A C K SYNACK SYNACK报文段后,客户端为该连接分配缓存和变量。
随后向服务器发送另一个报文段,该报文段是对服务器允许连接的报文段进行的确认;
该报文段将确认号字段被置为 s e r v e r _ i s n + 1 server\_isn+1 server_isn+1,因为连接已经完成了,所以 S Y N SYN SYN比特被置为0;该报文段可以携带应用层需要发送的数据。
3次握手解决:半连接和接收老数据问题
-
场景1:
服务器收到重传的连接请求后,会同一建立连接并向客户端发出应答(和2次连接无异)。
客户端收到服务器的响应后,会很发出拒绝连接的请求,服务器收到拒绝连接的请求后就会释放服务器端对于该连接的状态,避免维护没有必要的半连接。
-
场景2:
旧的数据被当成老的数据接收是因为有半连接的存在,因为场景1的问题被解决了,场景2的问题自然也被解决了。
当然也有可能在旧数据到达之前,双方又建立起了 T C P TCP TCP连接,但因为初始序号的随机选择,旧的数据也会因为序号不在范围内而被丢弃。
T
C
P
TCP
TCP是全双工通信,连接建立过程可以看作是两个方向上的连接建立过程,如下图所示;但中间的两条可以合并成一条,因此变成3次握手。
5.7 TCP:关闭连接
参与一条 T C P TCP TCP连接的两个进程中的任何一个都能终止该连接。连接释放后,主机中的“资源”(缓存和变量)将被释放。
所以客户端、服务器分别关闭他自己这一侧的连接。
- 通过发送 F I N FIN FIN比特位为1的 T C P TCP TCP报文段来关闭连接。
- 对方收到
F
I
N
b
i
t
=
1
FIN\ bit=1
FIN bit=1的报文段,用
A
C
K
ACK
ACK回应。
- 接到FIN段,ACK可以和它自己发出的FIN段一起发送(即 T C P TCP TCP关闭连接最少只需要3次握手)
- 当一方的 T C P TCP TCP连接断开之后,该方只能够接收数据而不能发送数据。
5.8 TCP状态描述(扩展)
在一个 T C P TCP TCP连接的生命周期内,运行在每台主机中的 T C P TCP TCP协议在各种TCP状态之间变迁。
5.8.1 客户TCP连接建立过程经历的状态
- 客户一开始处于CLOSED(关闭)状态;
- 客户向应用程序发起一个新的 T C P TCP TCP连接,这引起客户向服务器中 T C P TCP TCP发送 S Y N SYN SYN报文段;
- 发送报文段后,客户 T C P TCP TCP进入了 S Y N _ S E N T SYN\_SENT SYN_SENT状态,它等待来自服务器对客户请求连接的确认;
- 客户收到服务器的 S Y N b i t = 1 SYN\ bit=1 SYN bit=1的确认报文段,客户 T C P TCP TCP进入 E S T A B L I S H E D ESTABLISHED ESTABLISHED(已建立);
- 处在 E S T A B L I S H E D ESTABLISHED ESTABLISHED状态后,客户 T C P TCP TCP就能向服务器发送数据了。
5.8.2 客户TCP连接释放过程经历的状态
- 客户应用程序决定要关闭连接,这引起客户 T C P TCP TCP发送一个带有 F I N FIN FIN比特被置为1的 T C P TCP TCP报文段,并进入 F I N _ W A I T _ 1 FIN\_WAIT\_1 FIN_WAIT_1状态;
- 处于 F I N _ W A I T _ 1 FIN\_WAIT\_1 FIN_WAIT_1状态的客户在等待一个来自服务器的带有确认的 T C P TCP TCP报文段;
- 客户收到来自服务器的带有确认的 T C P TCP TCP报文段后,进入 F I N _ W A I T _ 2 FIN\_WAIT\_2 FIN_WAIT_2状态;
- 处于 F I N _ W A I T _ 2 FIN\_WAIT\_2 FIN_WAIT_2状态的客户在等待一个来自服务器的 F I N b i t = 1 FIN\ bit=1 FIN bit=1的报文段;
- 客户收到该报文段后,客户 T C P TCP TCP对报文段进行确认,并进入 T I M E _ W A I T TIME\_WAIT TIME_WAIT状态。(假定 A C K ACK ACK丢失, T I M E _ W A I T TIME\_WAIT TIME_WAIT状态使客户 T C P TCP TCP能够重传最后的确认报文段)
服务器端 T C P TCP TCP经历的典型的 T C P TCP TCP状态序列如下:
六、拥塞控制原理
6.1 拥塞控制概述
拥塞的非正式定义:
太多的数据需要网络传输,超过了网络的处理能力。
拥塞的表现:
- 分组丢失(路由器缓冲区溢出)
- 分组经历比较长的延迟(在路由器的队列中排队)
因此,分组重传作为网络拥塞的征兆
6.2 拥塞的原因/代价
6.2.1 场景1:2个发送方和一台具有无穷大缓存的路由器
场景环境:
- 一个路由器,具有无限大的缓存
- 2个发送端,2个接收端
- 输出链路带宽:R
- 没有重传
A
A
A主机和
B
B
B主机都以
λ
i
n
λ_{in}
λin字节/秒的平均速率将数据发送到连接中。
下图显示单条连接的吞吐量(接收方每秒接收的字节数)与该连接发送速率之间的函数关系:
当发送速率在
0
R
/
2
0~R/2
0 R/2之间时,接收方的吞吐量等于发送方的发送速率;
当发送速率超过
R
/
2
R/2
R/2时,接收方的吞吐量只能达到
R
/
2
R/2
R/2。该上线是由于两条连接之间共享链路容量造成的。
取得
R
/
2
R/2
R/2的吞吐量可能会加大数据传输的延迟,如下图;当发送速率接近
R
/
2
R/2
R/2,平均时延就会越来越大。
当超过
R
/
2
R/2
R/2时,路由器中的平均分组数就会无限增长,平均时延也会变成无穷大
所以拥塞的代价:
流量强度越大,延时就越大,强度趋近1时延时将趋近无穷大
6.2.2 场景2:2个发送方和一台具有有限缓存的路由器
场景环境:
- 一个路由器,有限的缓冲(当分组到达一个已满的缓存时会被丢弃)
- 2个发送端,2个接收端
- 输出链路带宽:R
- 分组丢失时,发送端重传
- 应用层的输入=应用层输出: λ i n = λ o u t λ_{in}=λ_{out} λin=λout
- 传输层的输入包括重传: λ i n ′ ≥ λ i n λ^{'}_{in}≥λ_{in} λin′≥λin
发送报文段(包含原始数据和重传数据)的速率用 λ i n ′ λ^{'}_{in} λin′字节表示, λ i n ′ λ^{'}_{in} λin′有时也被称为网络的供给载荷
假设发送方仅当在确定了一个分组已经丢失时才重传(如将超时时间设置的足够长);在这种情况下,性能就可能如下图所示;
探究供给载荷 λ ′ = R / 2 λ^{'}=R/2 λ′=R/2时的情况,数据交付给接收方的速率为 R / 3 R/3 R/3;从平均的角度来说,在 0.5 R 0.5R 0.5R的传输数据中, 0.333 R 0.333R 0.333R字节/秒是初始数据,而 0.166 R 0.166R 0.166R字节/秒是重传数据。
在此处,网络拥塞的代价是:
发送方必须执行重传以补偿因为缓存溢出而丢弃的分组
假设发送方会提前重传发生超时并重传在队列中在排队还未丢失的分组;这种情况初始数据和重传分组都可能到达接收方;在这种情况下路由器转发重传的分组是在做无用功,因为初始数据可能到达接收方。而路由器可以利用链路的传输能力去发送其他真正需要发送的分组。
因此,网络拥塞的代价是:
发送方在遇到大时延时时所进行的不必要重传会引起路由器利用其链路带宽来转发不必要的分组副本
6.2.3 场景3:4个发送方和具有有限缓存的多台路由器及多跳路径
(简单概述)
场景环境:
- 多个路由器,有限的缓冲
- 多个发送端
- 分组丢失时,发送端重传
分组超时时,发送时重传
假设
A
A
A要与
C
C
C通信,需要通过
R
1
R1
R1和
R
2
R2
R2路由
B
B
B要与
D
D
D通信。
B
B
B要与
D
D
D通信,需要通过
R
4
R4
R4和
R
1
R1
R1路由
B
B
B要与
D
D
D通信。
当 A A A向 C C C发送的数据量很大时,会占用 R 1 R1 R1路由的链路资源;而 B B B向 D D D发送数据时,会通过 R 1 R1 R1,若 R 1 R1 R1缓存满了,就会丢弃 B B B的通过 R 4 R4 R4传递过了的数据,从而浪费了 R 4 R4 R4的传输能力。
因此,网络拥塞的代价:
当一个分组沿着一条路径被丢弃时,每个上游路由器用于转发该分到丢弃该分组而使用的传输容量最终被浪费掉了。
6.3.4 总结
网络拥塞时:
- 需要增加泵出,来使之达到正常的接收
- 需要重传很多没有必要重传的数据
- 经过很多跳路由器的数据被抛弃,从而浪费了该数据的上游能力
七、TCP 拥塞控制
7.1 拥塞控制方法
2种常用的拥塞控制方法:
- 端到端拥塞控制:
- 没有来自网络的显式反馈
- 端系统根据延迟和丢失事件推断是否有拥塞
- T C P TCP TCP采用的方法
- 网络辅助的拥塞控制:
- 路由器提供给端系统以反馈信息
- A T M ATM ATM网络采用的方法
7.2 ATM ABR拥塞控制
A B R ( a v a i l a b l e b i t r a t e ) ABR(available\ bit\ rate) ABR(available bit rate)提供的是“弹性服务”:
- 如果发送端的路径"轻载"(不拥塞),那么发送方使用可用的全部带宽
- 如果发送方的路径拥塞了,发送方限制其发送的速度到一个最小保障速率上
发送方与接收方发送的数据以信元为单位,包含 ( 1 ) (1) (1)数据信元; ( 2 ) R M (2)RM (2)RM(资源管理)信元;
发送端在发送数据时,会在数据信元中间隔插入 R M RM RM信元; R M RM RM信元存在一些控制信息:
- N I b i t : NI\ bit: NI bit:no increase in rate (轻微拥塞)速率不要增加了
- C I b i t CI\ bit CI bit: congestion indication 拥塞指示
上述比特位会由中间经过的路由器进行标记,当接收端收到
R
M
RM
RM信元,会不做任何该变返回给发送端。
发送方会根据返回的
R
M
RM
RM信元的控制信息进行发送速率的调整。
7.3 TCP拥塞控制机制
T C P TCP TCP采用的是端到端的拥塞控制机制,端系统根据自身得到的信息,判断是否发生拥塞,从而采取动作。
拥塞控制的几个问题:
- 如何检测拥塞
- 是否是轻微拥塞
- 是否是拥塞
- 控制策略
- 在拥塞发送时如何动作,降低速率
- 轻微拥塞,如何降低
- 拥塞时,如何降低
- 在拥塞缓解时如何动作,增加速率
- 在拥塞发送时如何动作,降低速率
7.3.1 拥塞感知
发送端如何探测到拥塞?
- 某个段超时了(丢失事件 ):拥塞
- 事件:超时时间到,某个段的确认没有来
- 原因1:网络拥塞(某个路由器缓冲区没空间了,被丢弃)概率大
- 原因2:出错被丢弃了(各级错误,没有通过校验,被丢弃)概率小
- 原因2的概率比较小,所以
一旦超时,就认为拥塞了,有一定误判,但是总体控制方向是对的
- 有关某个段的3次重复ACK:轻微拥塞
- 收到3个冗余ACK,说明接收端没有按序收到报文段,收到的报文段序号中间出现了间隔;网络这时还能够进行一定程度的传输,可能发生了轻微拥塞
7.3.2 速率控制方法
如何控制发送端发送的速率?
- 维持一个拥塞窗口的值: C o n g W i n CongWin CongWin
- 发送端限制已发送但是未确认的数据量的上限:
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≤CongWin LastByteSent−LastByteAcked≤CongWin
即发送缓存大小上限为拥塞窗口的值 - 从而粗略地控制发送方的往网络中注入的速率
r a t e = C o n g W i n R T T b y t e s / s e c rate=\frac{CongWin}{RTT}\ bytes/sec rate=RTTCongWin bytes/sec
C o n g W i n CongWin CongWin是动态的,是感知到的网络拥塞程度的函数:
- 当发生超时或收到3个冗余ACK时, C o n g W i n CongWin CongWin减少
- 否则(正常收到Ack,没有发送以上情况): C o n g W i n CongWin CongWin跃跃欲试增大
TCP拥塞控制和流量控制的联合动作:
流量控制是发送端与接收端之间的局部约束,而拥塞控制是整个网络的全局约束。
发送端在控制往网络中注入数据的速率时,既要考虑双方之间的局部约束,也要考虑网络的全局约束。所以发送缓存满足:
S
e
n
d
W
i
n
=
m
i
n
{
C
o
n
g
W
i
n
,
R
e
c
v
W
i
n
}
SendWin=min\{CongWin, RecvWin\}
SendWin=min{CongWin,RecvWin}
7.3.3 拥塞控制策略概述
T C P 慢 启 动 : \color{red}{TCP慢启动:} TCP慢启动:
- 连接刚建立,
C
o
n
g
W
i
n
=
1
M
S
S
CongWin=1MSS
CongWin=1MSS
- 这里的MSS可以是1460byte,传输层最大报文段长度
- 当连接开始时,指数性增加发送速率,直到发生丢失的事件
指数性增长方式是指:
只要不发生超时或者收到3个冗余ACK,每一个RTT,
C
o
n
g
W
i
n
CongWin
CongWin加倍;即每收到一个ACK,
C
o
n
g
W
i
n
加
1
CongWin加1
CongWin加1。
虽然较慢启动,但一点都不慢;初始速率很慢,但是加速却是指数性的。所以在慢启动阶段, C o n g W i n CongWin CongWin值飞快增长。
所以从长期来看,慢启动的事件可以忽略不记。
超 时 事 件 发 生 : \color{red}{超时事件发生:} 超时事件发生:
-
乘 性 减 : \color{blue}{乘性减:} 乘性减:
发生丢失事件后将 C o n g W i n CongWin CongWin降为 1 1 1,将 C o n g W i n / 2 CongWin/2 CongWin/2作为阈值,进入慢启动阶段(倍增直到 C o n g W i n / 2 CongWin/2 CongWin/2) -
加 性 增 : \color{blue}{加性增:} 加性增:
当 C o n g W i n > CongWin> CongWin>阈值时,一个 R T T RTT RTT如没有发生丢失事件 ,将 C o n g W i n CongWin CongWin加 1 M S S 1MSS 1MSS;即每个 R T T RTT RTT, C o n g W i n CongWin CongWin加一。
收 到 3 个 冗 余 A C K : \color{red}{收到3个冗余ACK:} 收到3个冗余ACK:
- 阈值设置为 C o n g W i n / 2 CongWin/2 CongWin/2
- 进入拥塞避免模式: C o n g W i n CongWin CongWin设置为阈值,之后线性增长,每个 R T T RTT RTT增加 1 M S S 1MSS 1MSS
在旧版本种,无论是遇到超时事件还是收到3个冗余ACK,都会将阈值设置为 C o n g W i n CongWin CongWin的一半,并将 C o n g W i n CongWin CongWin设置为1。
在此基础上引入快重传和快恢复:
- 快重传:
当收到3个冗余的ACK,直接重传对方未收到的报文段,而不是等待超时计时器的超时- 快恢复:
当收到3个冗余ACK,将 阈 值 阈值 阈值设置为 C o n g W i n CongWin CongWin的一半,并将 C o n g W i n CongWin CongWin设置为1如下图:
7.3.4 总结
- 当 C o n g W i n < T h r e s h o l d ( 阈 值 ) CongWin<Threshold(阈值) CongWin<Threshold(阈值), 发送端处于慢启动阶段 ( s l o w − s t a r t ) (slow-start) (slow−start), 窗口指数性增长。
- 当 C o n g W i n > T h r e s h o l d CongWin>Threshold CongWin>Threshold, 发送端处于拥塞避免阶段 ( c o n g e s t i o n − a v o i d a n c e ) (congestion-avoidance) (congestion−avoidance), 窗口线性增长。
- 当收到三个重复的
A
C
K
s
(
t
r
i
p
l
e
d
u
p
l
i
c
a
t
e
A
C
K
)
ACKs (triple duplicate ACK)
ACKs(tripleduplicateACK),
T h r e s h o l d Threshold Threshold设置成 C o n g W i n / 2 CongWin/2 CongWin/2, C o n g W i n = T h r e s h o l d + 3 CongWin=Threshold+3 CongWin=Threshold+3。- 加上3是基于数据包守恒来说的,既然已经收到了3个冗余ACK,说明有三个数据分段已经到达了接收端,既然三个分段已经离开了网络,那么就是说可以在发送3个分段了
- 当超时事件发生时 t i m e o u t timeout timeout, T h r e s h o l d = C o n g W i n / 2 Threshold=CongWin/2 Threshold=CongWin/2、 C o n g W i n = 1 M S S CongWin=1 MSS CongWin=1MSS,进入 S S SS SS(慢启动)阶段
7.4 TCP 吞吐量
TCP的平均吞吐量是多少,使用窗口window尺寸W和RTT来描述?
首先忽略慢启动阶段,假设发送端总有数据传输。
那么窗口尺寸变化可以如下图所示:
可发生数据大小的窗口值在
W
/
2
−
W
W/2 - W
W/2−W之间变化,这里取均值作为平均窗口大小,即
W
2
+
W
2
=
3
4
W
\frac{\frac{W}{2}+W}{2}=\frac{3\ }{4}W
22W+W=43 W,所以吞吐量公式为:
平
均
吞
吐
量
=
3
4
W
R
T
T
b
y
t
e
s
/
s
e
c
平均吞吐量=\frac{\frac{3\ }{4}W}{RTT} bytes/sec
平均吞吐量=RTT43 Wbytes/sec
7.5 TCP公平性
公平性目标:
如果
K
K
K个
T
C
P
TCP
TCP会话分享一个链路带宽为
R
R
R的瓶颈,每一个会话的有效带宽为
R
/
K
R/K
R/K.
以简单的两条连接为例子,如下图:
假设 1 1 1和 2 2 2之间一开始是不公平的, 1 1 1占用了大量的带宽,如下图:
下一把,
T
C
P
TCP
TCP连接1和2会将拥塞窗口加1,红点向45°的方向移动:
因为超出链路带宽
R
R
R了,就会出现丢失;则将窗口值设为一半,如下图:
可以发现总体趋势是向公平分配的方式迈进的,上述的过程会重复多次,最后会收敛于绿线与蓝线的交点,即 1 1 1和 2 2 2各占 R / 2 R/2 R/2
而对于 U D P UDP UDP来说,发送的速率不受限制,想发就发, U D P UDP UDP对 T C P TCP TCP来说是"不友好"的。
学习完上述内容后,可以看出 T C P / I P TCP/IP TCP/IP框架将复杂性放在了网络边缘,从而减轻了网络核心的负担。