粘包、拆包问题是处于网络比较底层的问题,在数据链路层、网络层以及传输层都有可能发生。我们日常的网络应用开发大都在传输层进行,由于UDP有消息保护边界,不会发生这个问题,因此这篇文章只讨论发生在传输层的TCP粘包拆包问题。
消息保护边界:保护消息边界,就是指传输协议把数据当作一条独立的消息在网上传输,接收端只能接收独立的消息
TCP为流式传输、UDP为报式传输;
对于TCP而言,数据包的发送次数取决于TCP发送缓冲区的大小设置,如果多个数据包相加仍小于发送缓冲区的大小,则可以一次性发送完。
对于UDP而言,不管我们使用多大的接收缓冲区去接收数据,有多少个数据包,我们就必须要接收多少次
常说的TCP丢包,并不是将数据包遗失,而是一次接收了多个数据包通过包头直接解析了第一个包,误以为丢包;
TCP粘包/分包的原因:
应用程序写入的字节大小大于套接字发送缓冲区的大小,会发生拆包现象,
而应用程序写入数据小于套接字缓冲区大小,网卡将应用多次写入的数据发送到网络上,这将会发生粘包现象;
进行MSS大小的TCP分段,当TCP报文长度-TCP头部长度>MSS的时候将发生拆包
如何处理粘包、拆包问题?
知道了粘包、拆包问题及根源,那么如何处理粘包、拆包问题呢?TCP本身是面向流的,作为网络服务器,如何从这源源不断涌来的数据流中拆分出或者合并出有意义的信息呢?通常会有以下一些常用的方法:
- 使用带消息头的协议、消息头存储消息开始标识及消息长度信息,服务端获取消息头的时候解析出消息长度,然后向后读取该长度的内容。
- 设置定长消息,服务端每次读取既定长度的内容作为一条完整消息。
- 设置消息边界,服务端从网络流中按消息编辑分离出消息内容。
- 封包: 封包就是给一段数据加上包头