RTT(往返时延)
RTT的估计和超时
tcp像很多其他的协议一样,超时的时候会重发,但是如何估计往返时间和设定超时时间是一个需要考虑的问题
估计往返时延
segment里面有SampleRTT,计算方式是一个segment发出的时间,到ack收到的时间,对于重发的segment则不进行计算
显然这个值会因为网络状况产生一些波动,为了估计一个典型的RTT. TCP维护一个平均值,EstimatedRTT:
$$
\mathtt{EstimatedRTT}=(1-\alpha)·\mathtt{EstimatedRTT}+\alpha·\mathtt{SampleRTT}
$$
其中常用的$\alpha$值为$0.125$
DevRTT
DevRTT是用来衡量SampleRTT波动程度的值,公式如下:
$$
\mathtt{DevRTT}=(1-\beta)·\mathtt{DevRTT}+\beta·\mid\mathtt{SampleRTT}-\mathtt{EstimatedRTT}\mid
$$
EstimatedRTT和DevRTT都是一个EWMA(指数加权移动平均值)
计算重发间隔
有了EstimateRTT和DevRTT,超时时间应当如何计算?首先它需要不小于EstimateRTT,但是又不能太大,防止延迟过高。
所以设置方式通常是在EstimateRTT上加一个margin,这个margin的值需要根据SampleRTT的波动情况来设置。因此TCP采用的方式是:
$$
\mathtt{TimeoutInterval}=\mathtt{EstimatedRTT}+4·\mathtt{DevRTT}
$$
推荐使用的初始值则是1秒,当发生超时时,TimeoutInterval会倍增,直到它被重新计算。
可靠的数据传输
TCP在IP协议的基础上提供了可靠的数据传输,解决了数据错误,丢包,重复和顺序错乱的问题。
TCP推荐只维护一个重发的计时器,尽管可能有很多还没有收到ACK的包
一个简化的模型
1 | NextSeqNum=InitialSeqNumber |
有了上述的简化模型我们就可以进行一些场景模拟了
场景一
- Host A向Host B发了一个包,seq=92, length=8 bytes,
- Host B向Host A发了一个ack=100,但是丢了
- timer时间到了,Host A重发了这个包
- Host B发现是收过的,直接给Host A发了ack=100
- Host A收到,继续正常工作
场景二
- Host A向Host B发了一个包,seq=92,length=8 bytes
- Host A向Host B发了一个包, seq=100,length=20 bytes
- Host B收到seq=92的包,发了一个ack=100
- Host B收到seq=100的包,发了一个ack=120
- 两个ack包没能在超时前收到,Host A重发了seq=92的包
- Host B收到seq=92的包,发了一个ack=120
- Host A开始发seq=120的包,继续正常工作
场景三
- Host A向Host B发了上述1.2.中的两个包
- Host B发了一个ack=100,丢了
- Host B发了一个ack=120
- Host A在超时前收到了sck=120
- Host A发送seq=120,继续正常工作
添加翻倍机制
在上述的简化模型中,加入如下机制:
每当timeout重发时,将TimeoutInterval翻倍,可以在网络拥塞时产生一些效果
在CSMA/CD中你会看到类似的做法。
快速重传
在简单的模型上进行修改,已达到如下效果:
- Host A向Host B连发了5个包
- Host B收到了第一个包,并发送了ack=100
- 第二个包丢了
- Host B在收到3,4,5时连发了三个ack=100
- Host A的timer还没有超时,但收到三个duplicated ack了
- Host A重发seq=100
1 | event: ACK received, with ACK field value of y |
流控制(暂时略过)
TCP连接管理
这部分关注的是TCP连接的建立和断开
三次握手
Step1
客户端向服务端发起请求,带有SYN,并且随机选择一个Seq值x,把报文段发到服务端
Step2
服务端收到报文段,分配TCP连接的缓冲区,初始化一些变量。
服务端发送一个SYN报文给客户端,ack=x+1,seq为随机值y
此报文称为SYNACK报文
Step3
客户端收到SYNACK,分配缓冲区,初始化一些变量。
向服务端发送ack=y+1,seq=x+1
四次挥手
Step1
客户端向服务端发送FIN报文
Step2
服务端向客户端发送ACK报文
Step3
服务端向客户端发送FIN报文
Step4
客户端向服务端发送ACK报文。
服务端收到ACK后将关闭,客户端等待一段时间后关闭