[转]网络基本功09-细说TCP重传
[转]网络基本功09-细说TCP重传
❝本文由Zhang_Jiawen发表于Dell Technology"网络基本功"
如有侵犯版权,还请这位头像萌萌的大姐姐前辈联系我商讨删帖,道歉,赔偿,下跪等事宜.
❞
TCP的主要任务是很简单:「打包和发送数据」。TCP与其他协议的不同之处在于使用滑动窗口来管理基本数据收发过程,同时确保数据流的有效及可靠传输,从而不致发送速率明显快于接收速率。本文将描述TCP是如何确保设备可靠、有效地进行传输的。首先阐述TCP检测丢失片段以及重传的基本方法,之后介绍TCP如何判断一个片段为丢失片段。
TCP片段重传计时器以及重传队列
检测丢失片段并对之重传的方法概念上是很简单的。每一次发送一个片段,就开启一个重传计时器。计时器有一个初始值并随时间递减。如果在片段接收到确认之前计时器超时,就重传片段。TCP使用了这一基本技术,但实现方式稍有不同。原因在于为了提高效率需要一次处理多个未被确认的片段,以保证每一个在恰当的时间重传。TCP按照以下特定顺序工作:
「放置于重传队列中,计时器开始」 包含数据的片段一经发送,片段的一份复制就放在名为重传队列的数据结构中,此时启动重传计时器。因此,在某些时间点,每一个片段都会放在队列里。队列按照重传计时器的剩余时间来排列,因此TCP软件可追踪那几个计时器在最短时间内超时。 「确认处理」 如果在计时器超时之前收到了确认信息,则该片段从重传队列中移除。 「重传超时」 如果在计时器超时之前没有收到确认信息,则发生重传超时,片段自动重传。当然,相比于原片段,对于重传片段并没有更多的保障机制。因此,重传之后该片段还是保留在重传队列里。重传计时器被重启,重新开始倒计时。如果重传之后没有收到确认,则片段会再次重传并重复这一过程。在某些情况下重传也会失败。我们不想要TCP永远重传下去,因此TCP只会重传一定数量的次数,并判断出现故障终止连接。
但是我们怎样知道一个片段被完全确认呢?重传是基于片段的,而TCP确认信息是基于序列号累积的。每次当设备A发送片段给设备B,设备B查看该片段的确认号字段。所有低于该字段的序列号都已经被设备A接收了。因此,当片段中所发送的所有字节的序列号都比设备A到设备B的最后一个确认号小的时候,一个从设备B发到设备A的片段被认为是确认了。这是通过计算片段中最后一个序列号结合片段的数据字段来实现的。
让我们以下图为例来说明一下确认和重传是怎样工作的。假设连接中的服务器发出了四个连续片段(号码从1开始)
「片段1」 序列号字段是1片段长度80。所以片段1中最后一个序列号是80。
「片段2」 序列号是81片段长度是120。片段2中最后一个序列号是200。
「片段3」 序列号是201片段长度是160。片段3中最后一个序列号是360。
「片段4」 序列号是361片段长度是140。片段3中最后一个序列号是500。
这些片段是一个接一个发送的,而无需等待前一个发送得到确认。这是TCP滑动窗口的一个主要优势(细说TCP滑动窗口)。
假设客户端接收到前两个传输,它会发回一条确认消息确认号为201。从而告知服务器前两个片段已经被客户端成功接收了,它们从重传队列中移除(并且服务器发送窗口右移200字节)。在接收到确认号361或更高的片段之前,片段3会保留在重传队列中;片段4需要确认号501或更高。
现在,让我们进一步假设传输过程中片段3丢失了,但片段4被接收到了。客户端将片段4保存在接收buffer中,但是不需要确认,因为TCP是累积确认机制——确认片段4表示片段3也接收到了,但实际上并没有。因此,客户端需要等待片段3。实际上,服务器端片段3的重传计时器会超时,服务器之后重传片段3。之后客户端收到,然后发送片段3和4的确认信息给服务器。
还有一个重要的问题,服务器将如何处理片段4呢?虽然客户端在等待片段3,服务器没有收到反馈,所以它并不知道片段3丢失了,同样它也不知道片段4发生了什么(以及接下来传输的数据)。很有可能客户端已经接收到了片段4但是不能确认,也有可能片段4也丢失了。一些实现中会选择仅仅重传片段3,也有些会把3和4都重传。
![image-20200730223836461](https://wmcoding.oss-cn-hangzhou.aliyuncs.com/wmcoding/image-20200730223836461.png)
最后一个问题是重传队列中所使用片段重传计时器的值。如果设置过低,会发生过量重传,如果设置过高,重传丢失片段会减弱性能。必须通过一个称为自适应重传的过程来动态调整这个值,接下来的章节会讲到。
本文使用 mdnice 排版
更多精彩内容,敬请关注公众号"吾码2016"
![wmcoding](https://wmcoding.oss-cn-hangzhou.aliyuncs.com/wmcoding.png)