1、概述
众所周知,TCP/IP是面向链接的可靠传输协议,但是问题是如何实现可靠传输的呢?在我看来,TCP/IP可靠传输的基础是滑动窗口协议和连续ARQ协议,配合着流量控制和拥塞控制,使得整个传输过程保证:
2、滑动窗口协议和连续ARQ协议
2.1、停止等待协议和自动重传请求(ARQ)
所谓停止等待协议就是每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组。但是在传输过程中可能出现意外,这时候就需要用到ARQ协议了,比如说:
2.1.1、B可能没有收到A发送的M1M1
这时候A就会有个超时计时器,当超时计时器到期时没收到B的确认报文,则A重新发送M1M1,因此必须保证以下几点:
2.1.2、A没有收到B的确认报文或确认报文迟到
发生确认丢失时,B会再一次收到A的重传分组M1M1,此时B会进行如下行动:
发生确认迟到时,A会再一次收到B的确认报文,这时候A收下并丢弃这个确认报文,并不做什么。
2.2、滑动窗口协议和连续ARQ协议
2.2.1、累积确认方式
为了提高信道的利用率,实际上采用了流水线传输的方案。如图:
这时就需要使用连续ARQ协议和滑动窗口协议。发送方和接收方各自维持着发送窗口和接受窗口,发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置。接收方一般采用累计确认方式,即接收方不必对收到的分组逐个发送确认,而是可以在收到几个分组后,对按序到达的最后一个分组发送确认,这样就表示:到这个分组位置的所有分组都已经正确收到了。
2.2.2、累积确认方式详细解析
由图可见,描述一个发送窗口的状态需要三个指针P1P1、P2P2、P3P3
P3−P1=AP3−P1=A 的发送窗口(通知窗口)
P2−P1=P2−P1=已发送但尚未收到确认的字节数
P3−P2=P3−P2=允许发送但尚未发送的字节数(可用窗口或有效窗口)
解析一:此时B没有收到序号为31的数据,因此只能对按序收到的数据中的最高的序号给出确认,即此时B的确认号还是30(因为B没有收到序号31的数据,只能发送序号30的确认号)
解析二:此时B收到了序号31的数据,那么B会进行如下处理:
A收到B的确认号后,就可以把发送窗口向前滑动3个序号,但P2P2指针不变
解析三:A在继续发送完序号42~53的数据后,指针P2P2和P3P3重合。发送窗口内的序号都已经用完,但还没有收到确认。由于发送窗口已满,可用窗口已减小到了零,因此必须停止发送。此时A设置了超时计时器,超时计时器到期时就重传这部分数据,重置超时计时器,知道收到B的确认为止。如果A收到的确认号落在发送窗口内,那么A就可以使发送窗口继续向前滑动,并发送新的数据。
2.2.3、发送缓存与发送窗口、接收缓存与接收窗口
发送缓存用来暂时存放(即发送窗口):
发送应用程序传送给发送方TCP准备发送的数据
TCP已经发送出但尚未收到确认的数据
接收缓存用来暂时存放:
按序到达的、但尚未被接收应用程序读取的数据
未按序到达的数据
2.2.4、发送缓存和接收缓存小结
A的发送窗口根据B的接收窗口设置,但是二者并以总是一样大
对于不按序到达的数据应如何处理,TCP彼岸准并无明确规定(一般都是临时保存在接收窗口中,等到字节流完整接收后再按序提交给上层的应用进程)
TCP要求接收方必须有累积确认的功能,这样子可以减少传输开销
2.2.5、超时重传时间的确定
由上可知,TCP的发送方在规定的时间内没有收到确认就要重传已发送的报文段。但是由于TCP的下层互联网环境,发送的报文段可能只经过一个高速率的局域网,也可能经过多个低速率的网络,并且每个IP数据报所选择的路由还可能不同,因此注定超时重传时间要动态变化。
2.2.5.1、加权平均往返时间(平滑的往返时间,RTTsRTTs)
TCP采用的一种自适应算法,每当第一次测量到RTT样本时,RTTsRTTs值就取为所测量到的RTT样本值。但以后每测量到一个新的RTT样本,就按下式重新计算一次RTTsRTTs:
新的RTTs=(1−α)∗(旧的RTTs)+α∗(新的RTT样本)新的RTTs=(1−α)∗(旧的RTTs)+α∗(新的RTT样本)
在上式中,0⩽α<10⩽α<1,若α接近零,则表示新的RTTs新的RTTs与旧的RTTs旧的RTTs值相比变化不大;若α接近1,则表示新的RTTs新的RTTs受RTT样本的影响较大(RTT值更新较快)。α推荐值为1/8,即0.125.
2.2.5.2、超时重传时间(RTO)
超时计时器设置的超时重传时间应略大于上面得出的RTTsRTTs,计算公式如下:
RTO=RTTs+4∗RTTDRTO=RTTs+4∗RTTD
2.2.5.3、RTT的偏差的加权平均值(RTTDRTTD)
RTTDRTTD与RTTsRTTs和新的RTT样本之差有关。当第一次测量时,RTTDRTTD取值为RTT样本的一般,在以后的测量中按下式计算,0⩽β<10⩽β<1,推荐取值1/4,即0.25:
新的RTTD=(1−β)∗(旧的RTTD)+β∗|RTTs−新的RTT样本|新的RTTD=(1−β)∗(旧的RTTD)+β∗|RTTs−新的RTT样本|
2.2.5.4、问题
假设发送出一个报文段。设定的重传时间到了,还没有收到确认。于是重传报文段。经过了一段时间后,收到了确认报文段。
那么,如何判定收到的确认报文是对先发送的报文段的确认,还是对后来重传的报文段的确认?
于是有了Karn算法,即在计算机加权平均RTTsRTTs时,只要报文段重传了,就不采用其往返时间样本。这样子得出的加权平均RTTsRTTs和RTO就较准确
但也会引起另外的问题,于是进行修正:报文段每重传一次,就把超时重传时间RTO增大一些,典型的做法就是取新的重传时间为2倍就得重传时间,当不再发生报文段的重传时,才根据上卖弄的式子计算重传时间。
3、流量控制
3.1、发送窗口的确认
链接建立时,B根据自己的接受缓存大小确定窗口值大小,然后告诉A,我的窗口有多大,然后A就根据B给出的窗口值构造自己的发送窗口(发送缓存不一定比接受缓存大)。如图,窗口有前沿和后沿两个指针,二者都只能前移。
3.2、发送窗口和接收窗口的同步
但是前沿指针和后沿指针前移不一定是同步的,可能发生如下情况,关键取决于B告诉A我还能接受多少数据,于是A就根据B提供的信息发送数据,特别注意发送方的发送窗口不能超过接收方给出的额接受窗口的数值。参考如下图:
3.3、持续计时器
假如B向A发送了零窗口的报文段后不久,B的接收缓存又有了一些存储控件。于是B向A发送了rwnd = 400的报文段。然而这个报文段在发送过程中丢失了。酱紫A就一直等待B发送的非零窗口的通知,B也一直等待A发送数据,导致死锁。
因此需要一个持续计时器,当TCP链接的一方收到对方的零窗口通知,就启动持续计时器。持续计时器时间到是就发送一个零窗口探测报文段,而对方就在确认这个探测报文段时给出了现在的窗口值。如果窗口仍为零,那么持续计时器就重新计时。如果不为零,则可以打破死锁。
4、拥塞控制
若网络中有许多资源同时出现供应不足,网络性能就要明显变化,整个网络的吞吐量将随着输入负荷的增大而下降,这就是拥塞。
拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不至于过载。
流量控制往往指点对点的通信量的控制,是一个端到端端额问题。
拥塞控制则是当整个挽留过的输入负载超过网络所能承受的时候,向发送方发送控制报文,冰雹苏发送端,必须放慢发送速率。
4.1、慢开始和拥塞避免
发送方维持一个拥塞窗口(cwnd)的状态变量。其大小取决于网络的拥塞程度,并且动态的在变化。发送方让自己的发送窗口小于或等于拥塞窗口。
慢开始的算法思路是:
发送窗口先设置cwnd = 1,发送第一个报文段,以后每收到一个报文段确认,cwnd加1
每经过一个传输轮次,拥塞窗口cwnd就加倍(即呈指数增长)
当cwnd大于ssthresh阀值时,改用拥塞避免算法1(加法增大)
假设增长到某值(如24),网络出现超时,此时将ssthresh值变为值的一半(如12)(乘法减小),让后将cwnd置1,重新采用慢开始算法,重复如上步骤。
拥塞避免算法的思路是:让拥塞窗口cwnd线性缓慢增长
4.2、快重传和快恢复
快重传的算法思路是:
快恢复的算法思路是:
4.3、发送窗口的上限
也就是说rwnd和cwnd中较小的一个控制发送方发送数据的速率
发送窗口的上限值 = Min[rwnd, cwnd]
4.4、随机早期检测RED
随机早期检测RED将TCP拥塞控制和网络层采取的策略联系起来。由于网络层中路由器的队列的尾部丢弃策略会影响TCP的拥塞控制,因此需要采用该策略避免网络中的全局同步现象。
4.4.1、平均队列长度LAVLAV
使路由器维持两个参数,即队列长度最小门限THminTHmin和最大门限THmaxTHmax,每当一个分组到达时RED组都先计算平均队列长度LAVLAV,具体算法思路是:
若平均队列长度小于最小门限THminTHmin,则把新到达的分组放入队列进行排队
若平均队列长度超过最大门限THmaxTHmax,则把新到达的分组丢弃
若平均队列长度在最小门限THminTHmin和最大门限THmaxTHmax之间,则按照某一概率p将新到达的分组丢弃
平均队列长度的计算:
平均队列长度LAV=(1−α)∗(旧的RTTs)+α∗(新的RTT样本)平均队列长度LAV=(1−α)∗(旧的RTTs)+α∗(新的RTT样本)
因此可见RED正常工作的关键就是选择好三个参数:THminTHmin、THmaxTHmax和p