为什么说TCP协议是可靠的
问题背景
- 日常面试时,几乎所有学过计算机的都知道,TCP协议是可靠的,UDP协议不可靠的。为什么TCP协议是可靠的?它用什么机制保证可靠呢?
提出问题
- 由于IP 数据包的 MTU 有长度限制, TCP报文段过大时,需要切割。切割之后发送出去,由于网络链路的不确定性,接收端接收到包的次序和发送次序很大概率是不一致的。接收端如何把接收到的“同一批”TCP报文段数据拼接成预期的二进制数据?
- 发送方发送了一个TCP报文,怎么样确认接收方接收到了这个报文?
- 发送方发送了一个TCP报文,接收端如何保证接收到的报文段的数据没有在途中被“其他人”篡改?
TCP协议的初级解决方案
-
采用序列号标识一个TCP报文
- TCP报文段头部的,有一个字段是序列号(Sequence)
- 接收端可以使用sequence对不同的TCP报文进行排序和拼接
- TCP报文段头部的,有一个字段是序列号(Sequence)
-
初级解决方案: ACK机制+确认号
- 接收方接收到序号为seq的TCP报文之后,期望接收到序列号为seq+1的TCP报文,确认号会填充seq+1
- ACK位会置为1,表示确认接收到TCP报文
- 超时未接收到ACK的情况下,发送端默认认为TCP报文段丢失,再次重发
- 接收方接收到序号为seq的TCP报文之后,期望接收到序列号为seq+1的TCP报文,确认号会填充seq+1
-
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协议的优化
- 采用滑动窗口机制,提升通信效率