重传计时器(Retransmession),持久计时器(Persistance),保活计时器(keep-alive)及时间等待(time-wait)
还是图形比较鲜明,一目了然
重传计时器
为了防止数据报丢失,当TCP发送一个报文时,就启动重传计时器,有2种情况:
1若在计时器超时之前收到了特定报文的确认,则撤消这个计时器;
2特定数据报在计时器超时前没有收到确认,则重传该数据报,并把计时器复位
关于计时器超时计算
要计算重传超时时间(RTO),首先需要知道往返时间(RTT-round trip time),计算RTT比较复杂
需要用到的几个变量
测量的RTT 即发送一个数据报都收到对它的确认所需时间,记为MRTT(TCP在任何时刻只能对一个RTT测量)
平滑的RTT(Smoothed RTT) 因为RTT对不同的往返有不同的数值,而且其起伏比较大,以致不能为重传超时做标准,所以需要平滑的RTT,记为SRTT它对和前一个SRTT加权平均
如下所示:
最初 -->没有数值
第一次测试后 -->SRTT=MRTT
其他任意次测试-->SRTT=(1-α)SRTT+αMRTT
α取值与现实无关,通常为1/8,即新的SRTT是7/8的旧SRTT和1/8的新的MRTT的和
RTT的偏差
大多数现实不仅使用SRTT,还计算RTT的偏差,记为DRTT,是基于SRTT和MRTT使用如下关系计算:
最初 -->没有数值
第一次测量后-->DRTT=MRTT/2
其他任意次测量后-->DRTT=(1-β)DRTT+β|SRTT-MRTT|
β通常为1/4
重传超时(RTO)
RTO的数值基于平滑的往返时间及其偏差,大多数使用下面的公式:
最初 -->初始值
在任意次测试后 -->RTO=SRTT+4DRTT
Karn算法
假如一个报文在传输期间没有被确认,因而有重传
当发送端收到对这个报文的确认时,它就无法知道该确认是对原来报文的确认,还是对重传报文的确认
新的RTT值要根据发送去时的时间来计算,即对于重传报文的计算要从重传报文发出时计时
Karn算法的解决方法是在计算新的RTT时不考虑重传报文的RTT
指数退避
在发生重传现象时,那其RTO是多少大多数TCP使用指数退避策略
每产生一次重传,其RTO值就加倍
持久计时器
前面在流量控制篇提到死锁现象
要解开死锁,TCP为每一个连接使用一个持久计时器
当发送端TCP接收到rwnd=0的确认时,就启动持久计时器,当计时器截止时间到时,发送端TCP需要发送一个特殊的报文,叫做探测报文
该报文只有1字节,有序号,但无需确认
探测报文提醒接收端TCP:确认已丢失,必须重传
持久计时器截止时间设置为重传时间的数值,但是,如果没有收到从接收端回来的响应,则需要发送另外一个探测报文,并将持久计时器的值加倍和复位
如果结果和上面一样,发送端继续发送探测报文,直到其截止时间增大到阈值(通常为60s)为止
在这以后,发送端每60s发送一个探测报文,直到窗口重新打开
保活计时器
在某些实现中要使用keeplive timer来防止两个TCP之间出现长时间的空闲
比如客户端打开了服务器端的连接,传送了一些数据,然后就保持静默了
也许该客户端除了故障,在这种情况下,这个连接就永远处于打开状态
保活计时器的解决方法为,当服务器端收到客户端的信息时,就把计时器复位,超时通常设置2小时
若服务器2小时还没有收到客户的信息,就发送探测报文
若发送10个同样的报文(每个相隔75s)还没有收到响应,就认为客户端出了故障,终止这个连接
TIME-WAIT计时器
Time-wait(2MSL)计时器在终止连接时使用,在前面的状态转换篇曾在图中出现过
设置该计时器的主要目的有:
1如果最后一个ACK报文丢失了,那么服务器TCP(它为最后的FIN设置了计时器)以为它的FIN丢失了,因而重传
如果客户端进入了closed状态,并在2MSL计时器超时之前就关闭了这个连接,那么它就永远无法收到这个重传的FIN报文,因而服务器端也就无法收到ACK,服务器就不能关闭这个连接
2MSL计时器可以使客户端等待足够长的时间,使得当ACK丢失了(一个MSL),可以等到下一个FIN的到来(另一个MSL)
如果在TIME-WAIT状态时一个新的FIN到达了,客户端就发送一个ACK,并重新启动这个2MSL计时器
2从一个连接发来的重复报文可能会在下一个连接中出现
假定客户和服务器已关闭这个连接,经过短暂时间又使用相同套接字打开一个连接
这样的新连接叫久连接的化身(incarnation)
那么前一个连接的报文可能会到达新的连接中,同时被解释为新连接的报文
为了避免这个问题,TCP规定这个化身必须经过2MSL以后才出现
原理四个主要方面:
一、tcp协议之连接建立、断开
二、tcp协议之超时重传
三、tcp协议之窗口管理
四、tcp协议之拥塞控制
TCP是一种面向有连接的协议,也就是说必须确认对方存在时才能发送数据而TCP通过检验和、序列号、确认应答、重发控制、连接管理、窗口控制等机制来实现可靠传输。
1 目的:TCP三次握手是客户端和服务器总共发三个数据包,通过三个数据包来确认主动发送能力和被动接收能力是否正常。
2 实质:通过指定的四元组(源地址、源端口、目标地址、目标端口)来建立TCP连接,同步双方各自发送序列号seq和确认号ACK,同时也会交换窗口大小信息
三次握手过程的实现方式就是交换序列号seq。
随便在网上找个地址,如果通过域名想看ip地址,可以ping下看连接。
① 19216837发送[SYN]报文段至222169228146,告知序列号x为0。
② 222169228146发送[SYN,ACK]报文段至19216837,告知序列号y为0,确认号ACK为x+1=1。
③19216837发送[ACK]报文段至222169228146,告知确认号ACK为y+1=1。
报文段中的其他参数:
MSS=1460 :允许从对方接收到的最大报文段,图中为1460字节(指承载的数据,不包含报文段的头部)。
win=8192 :滑动窗口的大小为8192字节。
SACK_PERM=1 :开启选择确认。为什么会使用SACK:tcp确认方式不是一段报文段一确认,而是采用累积确认方式。服务器接收到的报文段无序所以序列号也是不连续,服务器的接收队列会出现空洞情况。为了解决空洞,提前了解当前空洞,应对丢失遗漏,采取重传。提前了解方式就是通过SACK选项信息,SACK信息包含接收方已经成功接收的数据块的序列号范围。而SACK_PERM字段为1表明,选择开启了SACK功能。
网络层可能会出现丢失、重复、乱序的问题,tcp是提供可靠的数据传输服务的,为了保证数据的正确性,tcp协议会重传它认为的已经丢失的包。重传两种机制:一种基于时间重传,一种基于确认报文段提供的信息重传。
RTT :数据完全发送完(完成最后一个比特推送到数据链路上)到收到确认信号的时间(往返时间)。
RTO :重传超时时间(tcp发送数据时设置一个计时器,当计时器超时没有收到数据确认信息,引发超时而重传,判断的标准就是RTO)。
思考:发送序列号为1、2、3、4这4个报文段,但是出现了序列号2报文段丢失,怎么办?
发送端接收到seq1的确认报文(ACK=2)后,等待seq=2的确认报文。
接收端当收到序列号为3的报文(2已丢失),发送ack为4的确认报文,发送端正等待ack为2的确认报文,面对跳跃的报文,那么发送端会一直等待,直到超出指定时间,重传报文2。
为什么不跳跃确认呢?
tcp是累积确认方式,如果确认报文3,那么意味着报文1和报文2都已经成功接收。
超时处理方式:
思考:上面计时器是以时间为标准重传,那么可以通过确认报文的次数来决定重传。
发送端接收到seq1的确认报文(ACK=2)后,等待seq=2的确认报文。
接收端收到报文3、4、5,但是没收到报文2,那么接收端发送三个ACK为2的确认报文,发送端收到这个三个确认报文,重传报文2。
思考:如果快速重传中丢失包的地方很多(报文2,报文,7,报文9,报文30,报文300),那么需要从头到尾都重传,这很蛋疼?
思考:SACK重传对于接收到重复数据段怎样运作没有明确规定,通过DSACK重传可以让发送方知道哪些数据被重复接收了,而且明确是什么原因造成的。
发送端没有收到100-199的ACK包,超过指定时间,重传报文。
接收端都已经收到200-299的发送报文了,又来100-199是重复报文。再向发送端发送一个ACK报文,设置SACK 100-199,告知发送端,已经收到了100-199包,只是回应ACK包丢失。
发送端发送包100-199,由于网络延迟,一直没有达到接收端。
接收端连续发送三个ACK 200确认报文,触发快速重传,发送端收到了ACK 500的确认报文,表明之前的报文都已经交付成功。
接收端又收到了延迟的报文100-199,再次向发送端发送一个SACK 100-199的ACK 500报文。
发送端发现这是重复报文,判断为网络延迟造成的。
计时器重传:根据超时,重传。
快速重传:根据接收三次相同ACK报文,重传。
选择确认重传:根据接收端提供的SACK信息,重传。
DSACK重传:根据重复报文,明确丢失ACK报文还是网络延迟。
Category1:已发送且已确认(已经收到ACK报文的数据)。
Category2:已发送但未收到确认。
Category3:即将发送。
Category4:窗口移动前都不能发送。
可用窗口:46-51字节。
发送窗口:32-51字节。
RCVNXT:左边界
RCVWND:接收窗口
RCVNXT+RCVWND:右边界
接收端接收到序列号小于左边界,那么被认为重复数据而被丢弃。
接收端接收到序列号大于右边界,那么被认为超出处理范围,丢弃。
注意:tcp协议为累积ACK结构,只有当达到数据序列号等于左边界时,数据才不会被丢弃。
如果窗口更新ACK丢失,对于发送端,窗口左边界右移,已发送数据得到ACK确认之后,左右边界距离减小,发送端窗口会减小,当左右边界相等时,称为零窗口。零窗口之后:接收端发送窗口更新能会发生窗口更新ACK丢失。
<<tcp/ip 详解>>解释:
TCP是通过接收端的通告窗口来实现流量控制的,通告窗口指示了接收端可接收的数据量。
当窗口值变为0时,可以有效阻止发送端继续发送,直到窗口大小恢复为非零值。
当接收端重新获得可用空间时,会给发送端传输一个窗口更新告知其可继续发送数据。这样的窗口更新通常都不包含数据(纯ACK),接收端向发送端发送的窗口更新ACK可能丢失。结果双方处于等待状态,发生死锁。
解决方案:
发送端会采用一个持续计时器间歇性地查询接收端,看其窗口是否已增长。触发窗口探测,强制要求接收端返回ACK。发送几次探测,窗口大小还是0,那么断开连接。
出现SWS的情况:
① 接收端通告窗口太小。
② 发送端发送的数据太小。
解决方案:
① 针对接收端:不应通告小窗口值
[RFC1122]描述:在窗口可增至一个全长的报文段(接收端MSS)或者接收端缓存空间的一半(取两者中较小值)之前,不能通告比当前窗口更大的窗口值。标准:min(MSS , 缓存空间/2)。
② 针对发送端:不应发送小的报文
至少满足以下其一:
(1)可以发送MSS字节的报文。
window size >= MSS或者 数据大小>=MSS
(2)数据段长度>=接收端通告过的最大窗口值的一半,才可以发送。
收到之前发送的数据的ack回包,再发送数据,否则一直攒数据。
(3) -1 没有未经确认的在传数据或者-2 连接禁用Nagle算法。
tcp基于ACK数据包中的通告窗口大小字段实现了流量控制。
当网络大规模通信负载而瘫痪,默认网络进入拥塞状态,减缓tcp的传输。发送方和接收方被要求承担超负荷的通信任务时,采取降低发送速率或者最终丢弃部分数据的方法。
反映网络传输能力的变量称为拥塞窗口(cwnd)。
通告窗口(awnd)。
发送窗口swnd=min(cwnd,awnd)
目的:tcp在用拥塞避免算法探寻更多可用带宽之前得到cwnd值,帮助tcp建立ACK时钟。
[RFC5681] :在传输初始阶段,由于未知网络传输能力,需要缓慢探测可用传输资源,防止短时间内大量数据注入导致拥塞。慢启动算法针对这一问题而设计。在数据传输之初或者重传计时器检测到丢包后,需要执行慢启动。
拥塞窗口值:每收到一个ACK值,cwnd扩充一倍。所以假设没有丢包且每个数据包都有相应ACK值,在k轮后swnd= ,成 指数增长 。
SMSS是发送方的最大段大小。
慢启动阶段,cwnd会指数增长,很快,帮助确立一个慢启动阙值(ssthresh)。有了阙值,tcp会进入拥塞避免阶段,cwnd每次增长值近似于成功传输的数据段大小,成 线性增长 。
实现公式:cwnd+=SMSSSMSS/cwnd
刚建立连接使用慢启动算法,初始窗口为4,收到一次ACK后,cwnd变为8,再收到一次ACK后,cwnd变为16,依次继续,32、64,达到阙值ssthresh为64。
开始使用拥塞避免算法,设置ssthresh为ssthresh/2,值为32。重新从初始窗口4,线性递增到ssthresh=32。
当cwnd < ssthresh时,使用慢启动算法
当cwnd > ssthresh时,使用拥塞避免算法
应用快速恢复算法时机:启动快速重传且正常未失序ACK段达到之前。启动快速恢复算法。
实现过程:
① 将ssthresh设置为1/2 cwnd,将cwnd设置为ssthresh+3SMSS。
② 每接收一个重复ACK,cwnd值暂时增加1 SMSS。
③当接收到新数据ACK后,将cwnd设置为ssthresh。
参考:<<tcp/ip 详解>>
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)