TCP 协议灵魂问题,巩固你的网路底层基础( 四 )


007:能不能说说TCP报文中时间戳的作用?
timestamp是TCP报文首部的一个可选项 , 一共占10个字节 , 格式如下:
kind(1字节)+length(1字节)+info(8个字节)
其中kind=8 , length=10 , info有两部分构成:timestamp和timestampecho , 各占4个字节 。
那么这些字段都是干嘛的呢?它们用来解决那些问题?
接下来我们就来一一梳理 , TCP的时间戳主要解决两大问题:
计算往返时延RTT(Round-TripTime)防止序列号的回绕问题计算往返时延RTT
在没有时间戳的时候 , 计算RTT会遇到的问题如下图所示:

TCP 协议灵魂问题,巩固你的网路底层基础
文章图片
如果以第一次发包为开始时间的话 , 就会出现左图的问题 , RTT明显偏大 , 开始时间应该采用第二次的;
如果以第二次发包为开始时间的话 , 就会导致右图的问题 , RTT明显偏小 , 开始时间应该采用第一次发包的 。
实际上无论开始时间以第一次发包还是第二次发包为准 , 都是不准确的 。
那这个时候引入时间戳就很好的解决了这个问题 。
比如现在a向b发送一个报文s1 , b向a回复一个含ACK的报文s2那么:
step1:a向b发送的时候 , timestamp中存放的内容就是a主机发送时的内核时刻ta1 。 step2:b向a回复s2报文的时候 , timestamp中存放的是b主机的时刻tb,timestampecho字段为从s1报文中解析出来的ta1 。 step3:a收到b的s2报文之后 , 此时a主机的内核时刻是ta2,而在s2报文中的timestampecho选项中可以得到ta1,也就是s2对应的报文最初的发送时刻 。 然后直接采用ta2-ta1就得到了RTT的值 。防止序列号回绕问题
现在我们来模拟一下这个问题 。
序列号的范围其实是在0~2^32-1,为了方便演示 , 我们缩小一下这个区间 , 假设范围是0~4 , 那么到达4的时候会回到0 。
第几次发包发送字节对应序列号状态10~10~1成功接收21~21~2滞留在网络中32~32~3成功接收43~43~4成功接收54~50~1成功接收 , 序列号从0开始65~61~2???
假设在第6次的时候 , 之前还滞留在网路中的包回来了 , 那么就有两个序列号为1~2的数据包了 , 怎么区分谁是谁呢?这个时候就产生了序列号回绕的问题 。
那么用timestamp就能很好地解决这个问题 , 因为每次发包的时候都是将发包机器当时的内核时间记录在报文中 , 那么两次发包序列号即使相同 , 时间戳也不可能相同 , 这样就能够区分开两个数据包了 。
008:TCP的超时重传时间是如何计算的?
TCP具有超时重传机制 , 即间隔一段时间没有等到数据包的回复时 , 重传这个数据包 。
那么这个重传间隔是如何来计算的呢?
今天我们就来讨论一下这个问题 。
这个重传间隔也叫做超时重传时间(RetransmissionTimeOut,简称RTO) , 它的计算跟上一节提到的RTT密切相关 。 这里我们将介绍两种主要的方法 , 一个是经典方法 , 一个是标准方法 。
经典方法
经典方法引入了一个新的概念——SRTT(Smoothedroundtriptime , 即平滑往返时间) , 没产生一次新的RTT.就根据一定的算法对SRTT进行更新 , 具体而言 , 计算方式如下(SRTT初始值为0):
SRTT=(α*SRTT)+((1-α)*RTT)
其中 , α是平滑因子 , 建议值是0.8 , 范围是0.8~0.9 。
拿到SRTT , 我们就可以计算RTO的值了:
RTO=min(ubound,max(lbound,β*SRTT))
β是加权因子 , 一般为1.3~2.0 , lbound是下界 , ubound是上界 。
其实这个算法过程还是很简单的 , 但是也存在一定的局限 , 就是在RTT稳定的地方表现还可以 , 而在RTT变化较大的地方就不行了 , 因为平滑因子α的范围是0.8~0.9,RTT对于RTO的影响太小 。
标准方法
为了解决经典方法对于RTT变化不敏感的问题 , 后面又引出了标准方法 , 也叫Jacobson/Karels算法 。
一共有三步 。
第一步:计算SRTT , 公式如下:
SRTT=(1-α)*SRTT+α*RTT
注意这个时候的α跟经典方法中的α取值不一样了 , 建议值是1/8 , 也就是0.125 。
第二步:计算RTTVAR(round-triptimevariation)这个中间变量 。
RTTVAR=(1-β)*RTTVAR+β*(|RTT-SRTT|)
β建议值为0.25 。 这个值是这个算法中出彩的地方 , 也就是说 , 它记录了最新的RTT与当前SRTT之间的差值 , 给我们在后续感知到RTT的变化提供了抓手 。
第三步:计算最终的RTO:
RTO=μ*SRTT+?*RTTVAR
μ建议值取1,?建议值取4 。
这个公式在SRTT的基础上加上了最新RTT与它的偏移 , 从而很好的感知了RTT的变化 , 这种算法下 , RTO与RTT变化的差值关系更加密切 。
009:能不能说一说TCP的流量控制?
对于发送端和接收端而言 , TCP需要把发送的数据放到发送缓存区,将接收的数据放到接收缓存区 。