核心机制:确认应答和超时重传
核心机制一:确认应答
实现让发送方知道接受方是否收到数据
发送方发送了数据之后,接受方,一旦接收到了,就会给发送方返回一个"应答报文"告诉发送方"我已经收到了数据"
网络上会出现"后发先至"的情况
为了解决上述问题,就引入了"序号和确认序号"对于数据的传输进行标识
TCP 是字节流传输的
序号和确认序号是针对"字节"进行编号的
一个 TCP 数据报,包含多个字节,如何体现所有编号呢?
编号是连续递增的,要知道 TCP 载荷的第一个字节的编号是多少,后面的每一个字节的编号就都知道了
32 位序号和数据:填写数据报部分的第一个字节编号几就行了
同一个 TCP 连接,序号会连续累加,下一个数据报的序号在上一个数据报的最后一个的序号基础上继续递增
确认序号只在应答报文中生效
确认序号根据收到的数据的最后一个字节的序号进行加一来进行填充
这一位为 1 ,确认序号字段就会有效负责是属于"无效字段"
确认序号的含义:
1.所有 < 确认序号的数据,接收方已经收到了
2.发送方接下来应该是从确认序号的位置开始,继续发送数据
这样的规则,非常有用,会在后面的特性中,有所体会
确认应答,就是 TCP 实现可靠传输的,最关键机制之一
这个地方的长度有多少,就看你代码是怎么写的
确认应答,关键是,数据顺利到达,通过 ack 告知发送方
实际传输中,很有可能丢包的
TCP 核心机制二:超时从传
确认应答的重要补充,针对丢包的场景的
超时:发送方,判定是否出现丢包的条件
重传:发现数据丢包,就在发一次(概率性问题)
假设一个数据包,传输过程中,丢包的概率大概是 10%(相当大的数字)
连续传输两次,数据包至少一次到达对方的概率是多少?
1 - 10% * 10% => 99%
传输次数的增加,数据报到达对方的概率概率大幅度增加
计算机中,一般不喜欢"无限的等",最大等待时间"超时时间"
没有收到 ack 有两种情况~~
这种情况丢包之后重传,理所当然的
B 已经收到过一份数据了接下来又重传一次,B 这边同样的数据收到了两份~~
TCP 协议已经处理上述情况
TCP 在接受到数据的时候,会在操作系统内核中维护一个"接受缓冲区"(内存空间)
如果又收到了同一个数据,此时就可以根据数据的序号来在接受缓冲器中进行"去重"
确保应用程序,在进行 read 操作的时候,读到的数据不会出现重复
TCP 也会针对对收到的数据在接受缓冲器中进行从重新排序,数据传输可能出现"后发先至"
1 - 1000 先发的, 1001 - 2000 后发的
接受方先收到了 1001 - 2000,后收到了 1 - 1000
TCP 的处理方式是在 接受缓冲区里,针对收到的数据进行排序
应用程序读到数据的时候,读到的仍然是有效的数据
超时重传的超时时间不是固定的,动态变化的
随着超时重传的进行,如果还是没有收到 ack 仍然要继续重传,但是等待的超时时间会逐渐变长
通过重传之后,大幅度提升数据到达对方的概率,但是重传之后,还是没有收到 ack,只能说明,当前网络的丢包概率,远远不止 10%了,此时,网络大概率出现了非常严重的故障了,再次频繁重传,非但不会解决问题,甚至可能会加重网络的故障程度~~
没指望重传能成功,死马当活马医
重传次数 / 总的重传时间是有上限的,到达上限,重传还没成功, tcp 连接就会被"重置"(重置涉及到"复位报文") => 单方面的断开连接了.
RST 触发了一个复位报文,意味着这个链接就不要了
单方面通知
"释放链接"就相当于是删除掉之前保存的对方的信息
超时重传,TCP中,进行可靠传输的重要机制之一
是确认应答的补充
确认应答处理传输顺利的情况,超时重传处理丢包的情况
网络上很多资料关于这里讨论的是有问题的
"TCP 的可靠性是通过 三次握手 实现的"
实际上不是这样的
三次握手只是在建立连接之初,涉及到的环节.一旦连接建立好了,后续就没有 握手的事情了