当前位置: 首页 > news >正文

【Netty系列】解决TCP粘包和拆包:LengthFieldBasedFrameDecoder

目录

如何使用?

1. 示例代码(基于Netty)

2. 关键参数解释

3. 协议格式示例

4. 常见配置场景

场景1:长度字段包含自身

场景2:长度字段在消息中间

5. 注意事项

举个例子

完整示例:客户端与服务端交互流程

1. 服务端代码(含响应)

2. 客户端代码(含编码器)

3. 执行流程说明

4. 网络包结构示意图

5. 关键点总结


如何使用?

以下是使用 LengthFieldBasedFrameDecoder 解决 TCP 粘包/拆包问题的 完整代码示例关键解释


1. 示例代码(基于Netty)

// Server端代码示例
public class NettyServer {public static void main(String[] args) {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {// 关键:添加 LengthFieldBasedFrameDecoderch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024,    // maxFrameLength(最大帧长度)0,       // lengthFieldOffset(长度字段偏移量)4,       // lengthFieldLength(长度字段占4字节)0,       // lengthAdjustment(长度调整值)4        // initialBytesToStrip(跳过前4字节,因为长度字段已解析)));// 将ByteBuf转为String(按需替换为实际解码器)ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));// 自定义业务处理器ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) {System.out.println("Received message: " + msg);}});}});ChannelFuture future = bootstrap.bind(8080).sync();future.channel().closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}

2. 关键参数解释

LengthFieldBasedFrameDecoder 的构造函数参数如下:

参数

说明

maxFrameLength

允许的最大帧长度(防止内存溢出)

lengthFieldOffset

长度字段的起始偏移量(通常为0)

lengthFieldLength

长度字段占用的字节数(例如4字节表示int)

lengthAdjustment

长度字段值后的内容长度调整(若长度字段包含自身长度,需调整)

initialBytesToStrip

解析后跳过的字节数(例如跳过长度字段本身)


3. 协议格式示例

假设自定义协议格式如下(长度字段在前):

+--------+----------------+
| Length |   Actual Data  |
| 4字节  |   (变长内容)    |
+--------+----------------+

4. 常见配置场景

场景1:长度字段包含自身
// 长度字段包含自身(如总长度= Length字段长度 + 数据长度)
new LengthFieldBasedFrameDecoder(1024, 0, 4, -4, 0);
// lengthAdjustment = -4(扣除长度字段自身占用的4字节)
场景2:长度字段在消息中间
// 消息格式:[Header][Length][Data]
new LengthFieldBasedFrameDecoder(1024, 2, 4, 0, 6);
// lengthFieldOffset=2(跳过Header的2字节)
// initialBytesToStrip=6(跳过Header+Length字段)

5. 注意事项

  1. 参数匹配协议:必须与协议中长度字段的位置和计算方式一致。
  2. 编解码顺序LengthFieldBasedFrameDecoder 需作为第一个解码器添加到Pipeline。
  3. 异常处理:建议配合 ExceptionHandler 处理解码失败的情况。

通过这种方式,Netty 会自动根据长度字段切分完整的数据包,彻底解决粘包/拆包问题

举个例子


完整示例:客户端与服务端交互流程

1. 服务端代码(含响应)
public class NettyServer {public static void main(String[] args) throws InterruptedException {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {// 添加长度字段解码器ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4));// 字符串解码器ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));// 业务处理器(返回响应)ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) {System.out.println("[Server] Received: " + msg);// 返回响应(添加长度前缀)ctx.writeAndFlush("ACK: " + msg);}});}});ChannelFuture future = bootstrap.bind(8080).sync();future.channel().closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}
2. 客户端代码(含编码器)
public class NettyClient {public static void main(String[] args) throws InterruptedException {EventLoopGroup group = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap();bootstrap.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {// 添加编码器(为消息添加长度前缀)ch.pipeline().addLast(new MessageToByteEncoder<String>() {@Overrideprotected void encode(ChannelHandlerContext ctx, String msg, ByteBuf out) {byte[] bytes = msg.getBytes(CharsetUtil.UTF_8);out.writeInt(bytes.length); // 写入4字节长度字段out.writeBytes(bytes);      // 写入实际数据}});// 响应解码器(与服务端解码器对称)ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4));ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));// 业务处理器(打印响应)ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) {System.out.println("[Client] Received: " + msg);}});}});ChannelFuture future = bootstrap.connect("localhost", 8080).sync();// 发送两条测试消息(自动处理粘包)future.channel().writeAndFlush("Hello Netty");future.channel().writeAndFlush("Test Message");future.channel().closeFuture().sync();} finally {group.shutdownGracefully();}}
}

3. 执行流程说明

  1. 客户端发送消息
    • 编码器将字符串转换为 长度字段(4字节) + 实际数据 的二进制格式。
    • 示例消息 "Hello Netty" 的传输格式:
+----------+-----------------+
| 0x00000B | "Hello Netty"   |  // 0x00000B = 11字节(字符串长度)
+----------+-----------------+
  1. 服务端解析消息
    • LengthFieldBasedFrameDecoder 根据长度字段切分完整数据包。
    • StringDecoder 将二进制数据转为字符串,业务处理器打印并返回响应。
  1. 客户端接收响应
    • 服务端返回的 "ACK: Hello Netty" 同样通过长度字段编码。
    • 客户端解码器解析后打印响应信息。

4. 网络包结构示意图

客户端发送:
[Length=11][Data="Hello Netty"][Length=12][Data="Test Message"]服务端接收:
[Length=11][Data="Hello Netty"] → 完整解析为独立消息
[Length=12][Data="Test Message"] → 完整解析为独立消息服务端响应:
[Length=16][Data="ACK: Hello Netty"]
[Length=17][Data="ACK: Test Message"]

5. 关键点总结

  • 编码对称性:客户端和服务端的编解码器需匹配(长度字段位置一致)。
  • 自动分包LengthFieldBasedFrameDecoder 自动处理TCP流中的粘包/拆包。
  • 性能保障:基于长度字段的解析效率极高,适合高频数据传输场景。

运行示例后,你将在控制台看到完整的请求-响应日志,验证粘包问题的解决效果。

相关文章:

  • c++第三章练习题
  • Java工厂方法模式详解
  • Python训练打卡Day38
  • 蔡司(ZEISS)借助Celonis构建流程智能平台,为S/4HANA迁移奠定基础
  • 企业微信接入说明
  • spring事务的面试题 —— 事务的特性、传播机制、隔离机制、注解
  • JS分支和循环
  • 【LLM】FastAPI入门教程
  • # STM32F103 串口打印配置(HAL库)
  • 应急响应靶机-web2-知攻善防实验室
  • Lyra学习笔记 Experience流程梳理
  • DeepSeek 赋能数字孪生城市,筑牢应急管理智慧防线
  • VLAN的作用和原理
  • 【五子棋在线对战】一.前置知识的了解
  • 吴恩达MCP课程(2):research_server
  • Linux系统下安装配置 Nginx
  • Kanass入门教程- 事项管理
  • 机器视觉2D定位引导-合同要点重度讲解-技术要点及注意事项
  • Java-Character类静态方法深度剖析
  • C语言结构体的别名与创建结构体变量
  • 南昌企业网站建设费用/湖南手机版建站系统开发
  • 郑州网站建设哪家好怎么样/销售crm客户管理系统
  • 用哪个平台做网站好/seo优化收费
  • 企业专业网站设计公/网站搭建公司哪家好
  • 手机做任务赚钱的网站/ping站长工具
  • 网站开发在线测试平台/为企业策划一次网络营销活动