Reference
https://zhuanlan.zhihu.com/p/112317245
简单聊聊 TCP 的可靠性 - 知乎 (zhihu.com)
概述
当前我所熟知的TCP可靠主要是根据TCP的丢包重传和有序性。但是,是怎么样的原理实现了丢包重传和有序性呢这个我们慢慢道来。
TCP主要提供了检验和、序列号/确认应答、超时重传、最大消息长度、滑动窗口控制等方法实现了可靠性传输。
检验和checksum — 包损坏
checksum是一个16bit的数据,他根据我们的TCP报头Head、伪头部和数据信息Data,来计算。
感觉非常像消息长度呀
客户端接收到这个TCP报文的数据后也进行一个计算,计算后得到的信息与checksum进行比对。
- 如果计算结果符合期望值,说明数据包没有收到干扰/损坏
- 如果不符合期望,一般会直接丢弃该数据包
序列号seq — 乱序
在上面的图中有一个Sequence Number序列号,通过这个序列号,我们可以在客户端维护一个有序的TCP数据表。
如下图所示,假设初始 seq=1
,发送的第一个报文 A 的长度为 12, 那么发送第二个报文 B 的 seq=1+12=13
。
这样我们的TCP就可以判断B是否是A的下一个报文了。
接收方接收到多个报文后,可以基于 seq
对数据包进行升序排序,并且通过检查 seq
的值,可以判断接收的数据包之间是否有间隔。
除此之外,seq
使得 TCP 有能力处理重复数据包的问题(幂等),因为接收方可以根据 seq
判断出该数据包是不是已经被接收了,这样顺带还解决了数据冗余的问题。
应答机制ack — 丢包
注意大写ACK和小写ack是有区别的
大写ACK一般指的是报文的类型
小写ack指的就是这个 32bit 长的号码
ack
是一个与上面提到的seq
相同长度的32bit的值,ack
实际上就是对seq
的估计值,如上,假设客户端收到B,那么他要应答一个ack = 14
的ACK报文给服务器。服务器接收到了带有ack
的ACK报文并且通过一个比对就可以得到客户端是否接收到了发送的信息。
重传
以上都是在没有丢包的情况下讨论的,如果发生丢包了呢?这个时候就会产生重传。
- 发送方发送一个未被确认的数据包后就启动一个计时器
- 如果在指定时间内没有收到
ACK
, 发送方可以重传该报文
超时重传 + ACK 也有一个小问题,就是最开始提到的数据冗余问题。
重传数据包可能导致接收方接收到多个重复的数据包, 如果你还没忘记的话,这个可以通过前面一节说到的 seq
去解决。
实际上 TCP 的拥塞控制也是预防丢包的有效机制之一,有兴趣的同学可以去了解
延迟确认 阻塞控制 滑动窗口
先看这两篇吧:
https://zhuanlan.zhihu.com/p/112317245
简单聊聊 TCP 的可靠性 - 知乎 (zhihu.com)