若是TCP发生超时,这个过程是如何处理的?

为何须要重传?

TCP自己须要提供可靠的服务,方式之一就是确认接收方真的收到了数据,若是过了一段时间,即超时了,尚未收到确认的报文,认为报文可能被丢失,就从新传送报文,确保数据都能被收到html

超时发生重传不必定重传一样的报文段,能够从新分组发送一个较大的报文段,只要它不超过接收方声明的MSSlinux

为何要动态的计算超时时间?

网络流量和路由器在包的传输过程当中可能改变,所以RTT(Round Trip Time)也会变化,若是超时时间保持不变,假如RTT变的大了,可能出现ACK还在再发送的路上,却直接重发了包,形成没必要要的浪费算法

如何动态计算超时重传时间?

TCP经典算法RTT是:R <- αR + (1-α)M,重传时间为 RTO=Rβ缓存

其中M表示测量时间意思是发送一个某序列号的字节和接收到包含该序列号的确认之间的往返时间网络

α是一个推荐值为0.9的平滑因子: 对公式稍微作变形为 R <- (1-g)R + gM 并从新组合R<-R+g(M-R) ,假设R是对下一个测量结果的预估,那么 M-R 表示预估的结果和真实结果的误差,整个公式所代表的就是预估的结果加上部分的预估误差即为新的预估结果。误差可能包括两部分,1是噪音,具备必定的随机性,用Er表示,2是预估的错误,选用的R初始值有问题,用Ee表示,则 R<-R+g*Er+g*Ee ,对于Ee来说,它的目标是把预估的结果往正确的方向去靠拢,而Er因为存在必定的随机性,通过多个样本以后,可能最终影响的结果都互相抵消,那么对于预估来说,但愿Ee的因子要大些,Er的因子要小些,使得R的最终取值可以朝着正确的平均值去收敛,而对于Er来说不管g取何值都会使得结果往好的方向走,于是取g为0.1-0.2能作一个好的值,也就是说α取值为0.9,0.8便可tcp

R是估算的RTT的平均值ide

RTO表示重传超时时间(Retransmission Timeout)意思是若是超过这个时间尚未收到ack就从新发送code

β 是RTT的变异系数,当传输时间能够忽略不计的时候,最大时延和平均时延的变化最大,能够看作全部的时延都是由于处理所形成的,这个时候最大值是平均值的两倍,推荐β取值为2。【假设往返时间最大值是R,若是传输时延忽略不计,那么这两次变化的平均传输时延就是0.5R,也就说最大值是平均值的两倍】β取值,详见 https://tools.ietf.org/html/rfc813 第五章 和 jacobson算法 http://www.cs.binghamton.edu/~nael/cs428-528/deeper/jacobson-congestion.pdfcdn

这种衡量方式没有考虑到,RTT变化范围很大的时候,经典的RTO的变化跟不上,从而引发没必要要的重传,此时网络已经处于饱和状态,再重传更会增长网络负载htm

jacobson算法中提到 β取值为2,此时的负载最多为30%,远不能处理真实的状况

另外一个没有没有解决的问题是,假定一个分组被发送,当超时发生时,分组以更长的RTO进行重传,而后收到一个确认,那么收到的这个ACK是针对第一个分组仍是第二个分组呢?这种场景的解决方式是Karn算法,主要思想是超时和重传发生时,在重传数据的确认最后到达以前,不能更新RTT估算值

tcp协议当前实现估算超时时间的方法是什么?

使用jacobson算法,RTO依赖于被平滑的RTT和被平滑的均值误差,而不是均值的常数倍

实现代码https://elixir.bootlin.com/linux/v2.6.32/ident/tcp_rtt_estimator

如何避免分组被丢弃?

使用拥塞避免算法,它假定分组丢失就是由于网络发生了拥塞。发送方使用两个变量来作拥塞控制,一个是拥塞窗口cwnd,一个是慢启动阈值ssthresh,当cwnd小于等于ssthresh时使用慢启动,不然使用拥塞避免算法 。原则以下:

  1. 发送方发送的字节小于等于cwnd和接收方通告窗口大小的最小值
  2. 发生超时,即在超时定时器溢出时尚未收到ACK,ssthresh被设置为当前窗口大小的一半,cwnd被设置为1个报文段
  3. 接收到新ACK时,若是cwnd<=ssthresh,就执行慢启动,cwnd值加1,不然执行拥塞控制,cwnd增长1/cwnd

cwnd值加1会形成窗口按照指数方式增加,好比刚开始是1,那么当它收到ack以后,下次发送两个包,而后会收到两个ack,cwnd立马增加为4,依此类推

cwnd值增长1/cwnd是一种加性增加,每接收到cwnd个包才加1

收到重复ack以后怎么处理?

收到一个重复ack以后,其实没法确认是报文丢失仍是报文段从新排序引发的,所以会等待少许重复ack到来,通常会等待3个或者以上。若是连续收到3个或以上的重复ack,则断定可能报文丢失了,选择立马重传,而不须要等待超时定时器溢出,这种方式称为快速重传算法。接下来执行快速恢复算法,二者合并整个过程以下:

  1. 收到3个重复的ack以后,将ssthresh的值设置为当前拥塞窗口的一半。重传丢失的报文段,设置cwnd为ssthresh加上3倍的报文段大小【重发了3个,因此增长3个报文段】
  2. 每收到另外一个重复的ack,cwnd就增长1个报文段大小,若是新的cwnd容许发送,则发送1个分组
  3. 确认一个新的ACK到达时,设置cwnd为第一步中设置的ssthresh大小。

这个新的ACK应该是确认第一步中丢失的报文那一刻起发送的报文到第一步中重发的报文期间全部报文,包括第一步中重发的报文。

收到重复ack以后不执行慢启动(即设置cwnd为1),是由于收到重复的ack仅仅表示网络中有数据丢失了。对于接收方而言,只有收到另外一个报文段才会产生重复的ack,而该报文已经已经离开网络并进入接收方的缓存,说明,收发端之间数据仍然在流动,不须要执行慢启动来忽然减小数据流。 详见 tools.ietf.org/html/rfc200… 第4章

整个过程图例以下

状态转移为:

如何对上述过程当中涉及的指标进行初始化?

在较新的TCP实现中,有一个路由表来维持指标,包括:被平滑的RTT、被平滑的均值误差以及慢启动门限。一个TCP链接关闭时,若是已经发送了16个窗口的数据(这就足够多了),且目的节点的路由表不是默认的表向,就会存储起来。创建链接是(部分主动仍是被动),只要路由表中有对应的值,就用它初始化

TCP是如何处理给定链接返回的ICMP差错的?

TCP常见的ICMP差错包括源站抑制、主机不可达和网络不可达

  1. 主机不可达和网络不可达实际上都被忽略,由于它们被认为是一种短暂现象(可能场景包括路由器替换须要花费几分钟才恢复)。此时的TCP链接没有关闭,反而会发送引发差错的数据
  2. 源站抑制引发cwnd被设置为1个报文段大小,从而发起慢启动,可是慢启动的ssthresh不会变化

源站抑制指路由或者主机接收数据的速度比处理的速度快

附录

把书读薄(TCP/IP详解 卷一 第二十一章)

相关文章
相关标签/搜索