知乎上关于这个概念的讨论在这里传送门
厘清概念
- 英文中没有“粘包”这个术语,应为国人误定义了一种现象。
2. TCP是处理字节流的传输协议,发送的是字节流,接收的是字节流。
3. 一般讨论这个问题的主要是PHP中的Swoole开发者和java中的netty开发者。
在 swoole 的开发文档中明确的写出了 “TCP 粘包问题” 。
在 ”Netty精粹之TCP粘包拆包问题“ 一文中大谈特谈这个问题。
之所以会有人搞不清楚问题的本质是因为对网络基础知识的缺乏,因此本文要从7层协议说起。
基础知识
我们常挂在嘴边的 TCP/IP 协议是 TCP 协议和 IP 协议两种协议的组合以及在其之上构建的应用协议的集合,因此也叫TCP/IP 协议簇。
IP 协议是网络层协议(3层),TCP是传输层协议(4层),HTTP是应用层协议(7层)。
我们看看 OSI 模型是哪7层:
![d06dcbc1cf1febdbf3b894d77b59a3db.png](https://img-blog.csdnimg.cn/img_convert/d06dcbc1cf1febdbf3b894d77b59a3db.png)
最底层的以太网协议(Ethernet)规定了电子信号如何组成数据包(packet)。
IP 协议定义了一套自己的地址规则,称为 IP 地址。它实现了路由功能,允许某个局域网的 A 主机,向另一个局域网的 B 主机发送消息。
TCP特点有如下几个:
- TCP是面向连接的运输层协议
- TCP连接只能有两个端点
- TCP提供可靠交付
- TCP提供全双工通信
- 面向字节流
包的大小
以太网数据包(packet)的大小是固定的,最初是1518字节,后来增加到1522字节。其中, 1500 字节是负载(payload),22字节是头信息(head)。这个1500就是网络设备设置的MTU大小了,因此正常来说MTU只能比1500小,更详细的资料参考“以太网帧大小到底多大?”。
IP 数据包在以太网数据包的负载里面,它也有自己的头信息,最少需要20字节,所以 IP 数据包的负载最多为1480字节。
![33c38423e6efda26846f428b8743402d.png](https://img-blog.csdnimg.cn/img_convert/33c38423e6efda26846f428b8743402d.png)
TCP 数据包在 IP 数据包的负载里面。它的头信息最少也需要20字节,因此 TCP 数据包的最大负载是 1480 - 20 = 1460 字节。由于 IP 和 TCP 协议往往有额外的头信息,所以 TCP 负载实际为1400字节左右。
因此,发送一条有效内容1500字节的信息需要两个 TCP 数据包。
两个 TCP 数据包分别拆成1460字节+40字节,假设系统真的直接把这两个包发出去的话,则每个包还要额外发送的信息为20(TCP头)+20(IP头)+22(以太网头)。可见第二次发送存在极大的浪费。
![0141bf2d35c4b3abd519c907960ef1d7.png](https://img-blog.csdnimg.cn/img_convert/0141bf2d35c4b3abd519c907960ef1d7.png)
在Socket网络编程中,操作系统内核提供了send() recv()两个方法。
当应用程序调用Socket接口发送函数Send( ),发送1000个字节时,Send()立马返回,不阻塞(Non-Blocked)。试问此时这1000个字节到接收端了吗?不一定!TCP什么时候发、发送频率、发送间隔、包的尺寸大小不受应用程序的直接指挥,而是由自己的代码来进行控制。但无论如何,TCP还是有自己的服务承诺的:按照发送方的字节顺序将字节流按序提交给接收方应用程序!
发送方的Send()可以按照自己的节奏向TCP供应商灌入数据,如同机关枪一样,一秒钟60发子弹。但TCP的发送节奏和机关枪的发射节奏不完全相同,一秒钟可能是40发,也有可能是80发。如果接收方按照一秒60次的频率(和发送方频率相同)接收,造成的后果就是,要么Receive()到的数据是空的,要么Receive()到的数据是1460字节,或者其它的字节数。
程序员就会有疑问了:明明是按照一个包1000字节发送的,为何接收方接到的包尺寸为1460字节?
实际上我们的问题不是TCP的粘包问题,而是如何在TCP协议基础上设计应用协议,并保证接收方可以按顺序读取并解析到发送方希望发送的数据大小。
方案一:在发送的TCP数据前标明该数据的长度,接收方如果没有接收完该长度的数据则继续等待,直到读完或者超时异常终止。
方案二:参考HTTP协议,以文本传输,其中content-length标示了数据长度,而且特殊字符rn可以标示换行或终止等
在以上方案外,还可以参考其他各种基于TCP协议的应用层协议,或者自创协议并实现。
完
参考资料
TCP 协议简介 - 阮一峰的网络日志
及各种文中链接