TCP/IP 协议簇建立了互联网中通信协议的感念模型,该协议簇中的两个主要协议就是 TCP 和 IP 协议。TCP/ IP 协议簇中的 TCP 协议能够保证数据段(Segment)的可靠性和顺序,有了可靠的传输层协议之后,应用层协议就可以直接使用 TCP 协议传输数据,不再需要关心数据段的丢失和重复问题
TCP 协议与应用层协议
IP 协议解决了数据包的路由和传输,上层的 TCP 协议不再协议关注路由和寻址,那么 TCP 协议解决的是传输的可靠性和顺序问题,上层不再需要关系数据如何传输,只要写入 TCP 协议的缓冲区的数据,协议栈几乎可以保证数据的送达。
当应用层协议使用 TCP 协议传输数据时,TCP 协议可能会将应用层发送的数据分成多个包依次发送,而数据的接收方收到的数据段可能有多个『应用层数据包』组成,所以当应用层从 TCP 缓冲区中读取数据时发现粘连的数据包时,需要对收到的数据进行拆分。
也正是因为应用层的协议设计者不需要考虑那么多,从而使设计者对 TCP 的理解出现误差从而出现粘包问题,所以粘包并不是 TCP 协议的问题,而是应用层设计者对 TCP 的定义缺乏理解,缺乏设计应用层协议的设计经验导致的
- TCP 协议是面向字节流的协议,它可能会组合或者拆分应用层协议的数据;
- 应用层协议的没有定义消息的边界导致数据的接收方无法拼接数据;
例如 Nagel 算法,它就会在 tcp 层等待多个应用层传来的数据达到 MSS 或收到 ACK 才会发送缓冲区中的数据,以此来网络拥堵,并减少额外的开销
所以说如果应用层没有实现消息边界,无法在应用层重组数据包的话,自然也就出现了粘包拆包这类现象,至于消息边界的方法,最简单的就是基于长度或基于终结符即可
总结
TCP 协议粘包问题是因为应用层协议开发者的错误设计导致的,他们忽略了 TCP 协议数据传输的核心机制 — 基于字节流,其本身不包含消息、数据包等概念,所有数据的传输都是流式的,需要应用层协议自己设计消息的边界,即消息帧(Message Framing),我们重新回顾一下粘包问题出现的核心原因:
- TCP 协议是基于字节流的传输层协议,其中不存在消息和数据包的概念;
- 应用层协议没有使用基于长度或者基于终结符的消息边界,导致多个消息的粘连;