拆包粘包问题
假设有两个数据包分别是P1和P2,我们来看看在发送数据包P1 P2和接收到数据包的过程中会现哪些问题。
-
服务端完整的接收到了P1和P2数据包,没有发生拆包和粘包问题
-
服务端接收到了P1和P2粘在一起的数据包,发生了TCP粘包
-
服务端接第一次接收到了P1和P2的一半,第二次读取了P2的另一半,发生了TCP拆包
-
服务端第一次读取了P2和P1的一半,第二次读取了P1的另一半,发生TCP拆包
-
如果服务端TCP接收的滑窗比较小,服务端多次接收P1和P2,期间会发生多次拆包
发生的原因
应用程序相对于TCP,IP层等属于上层,下层协议有自己的处理逻辑,对于上层发过来的数据包,下层不了解上层的数据的具体含义。
- 应用程序写入的数据大于TCP缓冲区的大小。
- 进行MSS大小的TCP分段。
- 以太网帧的有效载荷大于MTU进行IP分片
关于上面2、3项本文不做展开讨论,可以简单理解为数据包在经过TCP IP层的时候,它们会根据自己的逻辑对数据包进行拆分处理。
解决的方式
- 消息定长。
- 分隔符。
- 将消息分为消息头和消息体,消息头中包含消息的总长度。
演示TCP粘包
对上篇博文的juejin.cn/post/744910… NioClientHandler类的channelActive()方法进行改造,向服务器发送一百次消息
可以看到服务端只打印了两次的消息,发生了粘包问题
使用Netty解决粘包问题
ChildChannelHandler 添加LineBasedFrameDecoder和StringDecoder
NettyClient添加LineBasedFrameDecoder和StringDecoder
LineBasedFrameDecoder是采用分隔符的方式防止粘包问题,它处理"/n"和"/r/n"为结尾的分隔符。StringDecoder是将数据解码为字符串格式
再看下结果,服务端可以正常收到客户端发来的100条消息了,没有出现粘包问题。