为什么说TCP协议是可靠的

问题背景

  • 日常面试时,几乎所有学过计算机的都知道,TCP协议是可靠的,UDP协议不可靠的。为什么TCP协议是可靠的?它用什么机制保证可靠呢?

提出问题

  1. 由于IP 数据包的 MTU 有长度限制, TCP报文段过大时,需要切割。切割之后发送出去,由于网络链路的不确定性,接收端接收到包的次序和发送次序很大概率是不一致的。接收端如何把接收到的“同一批”TCP报文段数据拼接成预期的二进制数据?
  2. 发送方发送了一个TCP报文,怎么样确认接收方接收到了这个报文?
  3. 发送方发送了一个TCP报文,接收端如何保证接收到的报文段的数据没有在途中被“其他人”篡改?

TCP协议的初级解决方案

  1. 采用序列号标识一个TCP报文

    • TCP报文段头部的,有一个字段是序列号(Sequence)
    • 接收端可以使用sequence对不同的TCP报文进行排序和拼接
  2. 初级解决方案: ACK机制+确认号

    • 接收方接收到序号为seq的TCP报文之后,期望接收到序列号为seq+1的TCP报文,确认号会填充seq+1
    • ACK位会置为1,表示确认接收到TCP报文
    • 超时未接收到ACK的情况下,发送端默认认为TCP报文段丢失,再次重发
  3. TCP报文头部字段检验和,检验报文段数据的checksum是否和接收到实际的报文段数据的checksum一致。不一致则丢弃

初级解决方案的问题

对于问题2的初级解决方案:存在两个问题
1.效率低的问题。
发送方保持发送 -> 等待ACK -> 发送 -> 等待ACK…的单线工作方式,这样的工作方式叫做 stop-and-wait。stop-and-wait 虽然实现了 TCP 通信的可靠性,但同时牺牲了网络通信的效率。同时,在等待ACK的时间段内,网络都处于闲置(idle)状态

2.有点小缺陷
如果当前的TCP报文段一直没有被确认,会导致后续的片段无法发送出去。

TCP协议的优化方案

  • 滑动窗口机制
    • 不展开,可查看参考链接中的图片序列,非常详细
    • TCP报文段首部带有一个窗口
    • 接收端减少了 ACK 回复所消耗的流量,因为采用的是累计 ACK 回复
    • 发送端在大多数情况下不会因为单个TCP报文段没有接收到ACK而被阻塞继续发送
    • seq和确认号的一个细节
      • 接收到接收到序列号为seq的TCP报文之后,发送的ACK报文的确认号不一定是seq+1,可能是seq+n(n-1是接收到序列号为seq的TCP报文段之前已经接收到的TCP报文段的个数)

总结

  • TCP协议可靠使用以下机制来保证

    • TCP报文段首部sequence字段唯一标识TCP报文段,也作为顺序的标识
    • TCP通信采用ACK+确认号的确认机制
    • TCP报文首部的checksum字段记录报文段数据的checksum
  • TCP协议的优化

    • 采用滑动窗口机制,提升通信效率

参考资料

posted @ 2019-10-27 13:19  HelloWooo  阅读(1859)  评论(0编辑  收藏  举报