Netty-TCP拆包粘包

127 阅读2分钟

拆包粘包问题

假设有两个数据包分别是P1和P2,我们来看看在发送数据包P1 P2和接收到数据包的过程中会现哪些问题。

image.png

  1. 服务端完整的接收到了P1和P2数据包,没有发生拆包和粘包问题

  2. 服务端接收到了P1和P2粘在一起的数据包,发生了TCP粘包

  3. 服务端接第一次接收到了P1和P2的一半,第二次读取了P2的另一半,发生了TCP拆包

  4. 服务端第一次读取了P2和P1的一半,第二次读取了P1的另一半,发生TCP拆包

  5. 如果服务端TCP接收的滑窗比较小,服务端多次接收P1和P2,期间会发生多次拆包

发生的原因

应用程序相对于TCP,IP层等属于上层,下层协议有自己的处理逻辑,对于上层发过来的数据包,下层不了解上层的数据的具体含义。

  1. 应用程序写入的数据大于TCP缓冲区的大小。
  2. 进行MSS大小的TCP分段。
  3. 以太网帧的有效载荷大于MTU进行IP分片

关于上面2、3项本文不做展开讨论,可以简单理解为数据包在经过TCP IP层的时候,它们会根据自己的逻辑对数据包进行拆分处理。

解决的方式

  1. 消息定长。
  2. 分隔符。
  3. 将消息分为消息头和消息体,消息头中包含消息的总长度。

演示TCP粘包

对上篇博文的juejin.cn/post/744910… NioClientHandler类的channelActive()方法进行改造,向服务器发送一百次消息

image.png

image.png 可以看到服务端只打印了两次的消息,发生了粘包问题

使用Netty解决粘包问题

ChildChannelHandler 添加LineBasedFrameDecoder和StringDecoder

image.png

NettyClient添加LineBasedFrameDecoder和StringDecoder

image.png LineBasedFrameDecoder是采用分隔符的方式防止粘包问题,它处理"/n"和"/r/n"为结尾的分隔符。StringDecoder是将数据解码为字符串格式

image.png 再看下结果,服务端可以正常收到客户端发来的100条消息了,没有出现粘包问题。