详解TCP:顺序和丢包问题

  为了保证顺序性,每一个包都有一个 ID。在建立连接的时候,会商定起始的 ID 是什么,然后按照 ID 一个个发送。假设A发给B的数据流由一个500 000字节的文件组成,MSS为1000字节。数据流的首字节ID为0,那么TCP会将这个文件分为500个报文段,每一个报文段的首部序号字段中分别为0、1000、2000...

 如果第二个报文段先于第一个到B,也就是包的顺序出错。TCP RFC中并没有详细描述对这种问题的处理,一般是工程师自己来解决。一般有两种方案:1)B立即丢弃失序报文段 2)B保留这个报文段,并等待缺少的字节来填补该间隔,第二种是常用的方法。

  为了保证不丢包,对于发送的包都要进行应答。具体是怎么实现的呢?比如发一个确认一个,很明显这样效率太低。TCP采用的是累计确认,例如确认号是5,代表5之前序号的包都收到了。A首部中的确认号是期望从B收到的下一个字节的序号。为了记录所有发送的包和就收的包,TCP发送端和接收端都用缓存来保存这些记录。发送端的缓存里是按照包的 ID 一个个排列根据处理的情况分成四个部分:

  • 发送了并且已经确认的
  • 发送了并且尚未确认的
  • 没有发送,但是已经等待发送的
  • 没有发送,并且暂时还不会发送的

为什么没有发送的要分为两种呢?这里就涉及到流量控制了。流量控制是一个 速度匹配服务,即发送方的发送速率与接收方应用程序的读取速率相匹配。 在 TCP 里,接收端会给发送端报一个窗口的大小,叫Advertised window。这个窗口的大小应该等于上面的2、3之和,就是已经交代了没做完的加上马上要交代的。超过这个窗口大小的,接收端做不过来,就不能发送了。发送端的数据结构如下:

对于接收端来讲,它的缓存里记录的内容要简单一些。第一部分:接受并且确认过的;第二部分:还没接收,但是马上就能接收的;第三部分:还没接收,也没法接收的。对应的数据结构为:

LastByteRead 之后是已经接收了,但是还没被应用层读取的;NextByteExpected 是第一部分和第二部分的分界线;MaxRcvBuffer:'大缓存的量;以上面的图为例,在发送端来看,1、2、3 已经发送并确认;4、5、6、7、8、9 都是发送了还没确认; 10、11、12 是还没发出的;13、14、15 是接收方没有空间,不准备发的。 在接收端来看,1、2、3、4、5 是已经完成 ACK,但是没读取的;6、7 是等待接收的;8、9 是已经接收,但是没有 ACK 的。

  发送端和接收端当前的状态为:

  • 1、2、3 没有问题,双方达成了一致。
  • 4、5 接收方说 ACK 了,但是发送方还没收到,有可能丢了,有可能在路上。
  • 6、7、8、9 肯定都发了,但是 8、9 已经到了,但是 6、7 没到,出现了乱序,缓存着但是没办法 ACK。

假设 4 的确认到了,不幸的是,5 的 ACK 丢了,6、7 的数据包丢了,这该怎么办呢?一种方法就是超时重试,即对每一个已经发送了但是没有 ACK 的包,都有设一个定时器,超过了一定时间,就重发。但是这个超时的时间如何评估呢?这个时间不宜过短,时间必须大于包的往返时间 RTT,否则会引起不必要的重传。也不宜过长,这样超时时间变长,访问就变慢了。如果过一段时间,5、6、7 都超时了,就会重新发送。接收方发现 5 原来接收过,于是丢弃 5;6 收到了,发送 ACK,要求下一个是 7,7 不幸又丢了。当 7 再次超时又需要重传的时候,TCP 的策略是超时间隔加倍。每当遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前值的两倍。两次超时,就说明网络环境差,不宜频繁反复发送。

  超时触发重传存在的问题是,超时周期可能相对较长。那是不是可以有更快的方式呢?就是快重传机制当接收方收到一个序号大于下一个所期望的报文段时,就检测到了数据流中的一个间格,于是发送三个冗余的 ACK,客户端收到后,就在定时器过期之前,重传丢失的报文段。例如,接收方发现 6、8、9 都已经接收了,就是 7 没来,那肯定是丢了,于是发送三个 6 的 ACK,要 求下一个是 7。客户端收到 3 个,就会发现 7 的确又丢了,不等超时,马上重发,这样明显缩短了超时周期。快重传在拥塞控制中也会用到,如何使用的细节在下一篇文章中讲解。还有一种方式称为Selective Acknowledgment (SACK)。这种方式需要在 TCP 头里加一个 SACK 的 东西,可以将缓存的地图发送给发送方。例如可以发送 ACK6、SACK8、SACK9,有了地图,发送方一下子就能看出来是 7 丢了。

 

参考资料:《趣谈网络协议》刘超

     《计算机网络:自顶向下方法》原书第六版 陈鸣译

posted @ 2020-07-21 10:20  今天你做题了吗  阅读(2453)  评论(0编辑  收藏  举报