tcp协议是一个可靠的协议。它通过重新发送(retransmission)来实现tcp片段传输的可靠性。简单的说,tcp会不断重复发送tcp片段,直到片段被正确接收。
tcp片段丢失
tcp头部的checksum
接收方(receiver)可以通过校验tcp片段头部中checksum区域来检验tcp片段是否出错。我们已经接触过了ip协议详解的checksum算法。tcp片段的checksum算法与之类似。ip协议的checksum只校验头部,tcp片段头部的checksum会校验包括ip头部、tcp头部和tcp数据在内的整个序列,确保ip地址、端口号和其他相关信息正确。如果tcp片段出错,接收方可以简单的丢弃改tcp片段,也就相当于tcp片段丢失。
tcp片段包裹在一个ip包中传输。ip包可能在网络中丢失。导致ip包丢失的原因可能有很多,比如ip包经过太多的路由器接力,达到hop limit;比如路由器太过拥挤,导致一些ip包被丢弃;再比如路由表(routing table)没有及时更新,导致ip包无法送达目的地。
下面我们要介绍两种重新发送tcp片段的机制:超时重新发送和快速重新发送。
超时重新发送
我们之前已经简单介绍过重新发送的机制:当发送方送出一个tcp片段后,将开始计时,等待该tcp片段的ack回复。如果接收方正确接收到符合次序的片段,接收方会利用ack片段回复发送方。发送方得到ack回复后,继续移动窗口,发送接下来的tcp片段。如果直到计时完成,发送方还是没有收到ack回复,那么发送方推断之前发送的tcp片段丢失,因此重新发送之前的tcp片段。这个计时等待的时间叫做重新发送超时时间(rto, retransmission timeout)。
rto:沙漏中沙子的多少
发送方应该在等待多长时间之后重新发送呢?这是重新发送的核心问题。上述过程实际上有往返两个方向:1. 发送片段从发送方到接收方的传输,2. ack片段从接收方到发送方的传输。整个过程实际耗费的时间称做往返时间(rtt, round trip time)。如果rtt是固定的,比如1秒,那么我们可以让rto等于rtt。但实际上,rtt的上下浮动很大。比如某个时刻,网络中有许多交通,那么rtt就增加。在rtt浮动的情况下,如果我们设置了过小的rto,那么tcp会等待很短的时间之后重新发送,而实际上之前发送的片段并没有丢失,只是传输速度比较慢而已,这样,网络中就被重复注入tcp片段,从而浪费网络传输资源。另一方面,如果rto时间过长,那么当tcp片段已经实际丢失的情况下,发送方不能及时重新发送,会造成网络资源的闲置。所以,rto必须符合当前网络的使用状况。网络状况越好,rto应该越短;网络状况越差,rto应该越长。
rtt: 往返时间
tcp协议通过统计rtt,来决定合理的rto。发送方可以测量每一次tcp传输的rtt (从发送出数据片段开始,到接收到ack片段为止),这样的每次测量得到的往返时间,叫做采样rtt(srtt, sampling round trip time)。建立连接之后,每次的srtt作为采样样本,计算平均值(mean)和标准差(standard deviation),并让rto等于srtt平均值加上四倍的srtt标准差。
rto = mean 4 std
(上述算法有多个变种,根据平台不同有所变化)
平均值反映了平均意义上的rtt,平均往返时间越大,rto越大。另一方面,标准差越大也会影响rto。标准差代表了rtt样本的离散程度。如果rtt上下剧烈浮动,标准差比较大。rtt浮动大,说明当前网络状况相对不稳定。因此要设置更长的rto,以应对不稳定的网络状况。
快速重新发送
我们刚才介绍了超时重新发送的机制:发送方送出一个tcp片段,然后开始等待并计时,如果rto时间之后还没有收到ack回复,发送方则重新发送。tcp协议有可能在计时完成之前启动重新发送,也就是利用快速重新发送(fast-retransmission)。快速发送机制如果被启动,将打断计时器的等待,直接重新发送tcp片段。
由于ip包的传输是无序的,所以接收方有可能先收到后发出的片段,也就是乱序(out-of-order)片段。乱序片段的序号并不等于最近发出的ack回复号。已接收的文本流和乱序片段之间将出现空洞(hole),也就是等待接收的空位。比如已经接收了正常片段5,6,7,此时又接收乱序片段9。这时片段8依然空缺,片段8的位置就是一个空洞。
补上空洞
tcp协议规定,当接收方收到乱序片段的时候,需要重复发送ack。比如接收到乱序片段9的时候,接收方需要回复ack。回复号为8 (7 1)。此后接收方如果继续收到乱序片段(序号不是8的片段),将再次重复发送ack=8。当发送方收到3个ack=8的回复时,发送方推断片段8丢失。即使此时片段8的计时器还没有超时,发送方会打断计时,直接重新发送片段8,这就是快速重新发送机制(fast-retransmission)。
快速重新发送机制利用重复的ack来提示空洞的存在。当重复次数达到阈值时,认为空洞对应的片段在网络中丢失。快速重新发送机制提高了检测丢失片段的效率,往往可以在超时之前探测到丢失片段,并重复发送丢失的片段。
总结
凤凰浴火重生。而tcp协议利用重新发送(retransmission)来实现tcp传输的可靠性。重新发送的基本形式是超时重新发送,根据统计的往返时间来设置超时标准;如果超时,则重新发送tcp片段。另一方面,快速重新发送则通过乱序片段的ack来更早的推断出片段的丢失。