为什么TCP是可靠的

Reference

https://zhuanlan.zhihu.com/p/112317245
简单聊聊 TCP 的可靠性 - 知乎 (zhihu.com)

概述

当前我所熟知的TCP可靠主要是根据TCP的丢包重传和有序性。但是,是怎么样的原理实现了丢包重传和有序性呢这个我们慢慢道来。

TCP主要提供了检验和、序列号/确认应答、超时重传、最大消息长度、滑动窗口控制等方法实现了可靠性传输。

检验和checksum — 包损坏

checksum是一个16bit的数据,他根据我们的TCP报头Head伪头部数据信息Data,来计算。

感觉非常像消息长度呀

ueda0

图1 checkesum

客户端接收到这个TCP报文的数据后也进行一个计算,计算后得到的信息与checksum进行比对。

  • 如果计算结果符合期望值,说明数据包没有收到干扰/损坏
  • 如果不符合期望,一般会直接丢弃该数据包

序列号seq — 乱序

在上面的图中有一个Sequence Number序列号,通过这个序列号,我们可以在客户端维护一个有序的TCP数据表。

如下图所示,假设初始 seq=1 ,发送的第一个报文 A 的长度为 12, 那么发送第二个报文 B 的 seq=1+12=13

这样我们的TCP就可以判断B是否是A的下一个报文了。

8evhk

图2 seq

接收方接收到多个报文后,可以基于 seq 对数据包进行升序排序,并且通过检查 seq 的值,可以判断接收的数据包之间是否有间隔

除此之外,seq 使得 TCP 有能力处理重复数据包的问题(幂等),因为接收方可以根据 seq 判断出该数据包是不是已经被接收了,这样顺带还解决了数据冗余的问题。

应答机制ack — 丢包

注意大写ACK和小写ack是有区别的
大写ACK一般指的是报文的类型
小写ack指的就是这个 32bit 长的号码

ack是一个与上面提到的seq相同长度的32bit的值,ack实际上就是对seq估计值,如上,假设客户端收到B,那么他要应答一个ack = 14ACK报文给服务器。服务器接收到了带有ackACK报文并且通过一个比对就可以得到客户端是否接收到了发送的信息。

重传

以上都是在没有丢包的情况下讨论的,如果发生丢包了呢?这个时候就会产生重传

  • 发送方发送一个未被确认的数据包后就启动一个计时器
  • 如果在指定时间内没有收到 ACK , 发送方可以重传该报文

eeqe1

图3 ack

超时重传 + ACK 也有一个小问题,就是最开始提到的数据冗余问题。

重传数据包可能导致接收方接收到多个重复的数据包, 如果你还没忘记的话,这个可以通过前面一节说到的 seq 去解决。

实际上 TCP 的拥塞控制也是预防丢包的有效机制之一,有兴趣的同学可以去了解

延迟确认 阻塞控制 滑动窗口

先看这两篇吧:

https://zhuanlan.zhihu.com/p/112317245
简单聊聊 TCP 的可靠性 - 知乎 (zhihu.com)