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

【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流中的粘包/拆包。
  • 性能保障:基于长度字段的解析效率极高,适合高频数据传输场景。

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

相关文章:

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

目录 如何使用&#xff1f; 1. 示例代码&#xff08;基于Netty&#xff09; 2. 关键参数解释 3. 协议格式示例 4. 常见配置场景 场景1&#xff1a;长度字段包含自身 场景2&#xff1a;长度字段在消息中间 5. 注意事项 举个例子 完整示例&#xff1a;客户端与服务端交互…...

stm与51单片机哪个更适合新手学

一句话总结 51单片机&#xff1a;像学骑自行车&#xff0c;简单便宜&#xff0c;但只能在小路上骑。 STM32&#xff1a;像学开汽车&#xff0c;复杂但功能强&#xff0c;能上高速公路&#xff0c;还能拉货载人&#xff08;做复杂项目&#xff09;。 1. 为啥有人说“先学51单片…...

【计算机网络】第3章:传输层—面向连接的传输:TCP

目录 一、PPT 二、总结 TCP&#xff08;传输控制协议&#xff09;详解 1. 概述 核心特性&#xff1a; 2. TCP报文段结构 关键字段说明&#xff1a; 3. TCP连接管理 3.1 三次握手&#xff08;建立连接&#xff09; 3.2 四次挥手&#xff08;终止连接&#xff09; 4. 可…...

从架构视角设计统一网络请求体系 —— 基于 uni-app 的前后端通信模型

在使用 uni-app 开发跨平台应用时&#xff0c;设计一套清晰、统一、可扩展的网络请求模块 是前期架构的关键环节。良好的请求模块不仅提高开发效率&#xff0c;更是保证后期维护、调试和业务扩展的基础。 一、网络请求设计目标 在uni-app中设计网络请求模块&#xff0c;应遵循…...

《信号与系统》--期末总结V1.0

《信号与系统》–期末总结V1.0 学习链接 入门&#xff1a;【拯救期末】期末必备&#xff01;8小时速成信号与系统&#xff01;【拯救期末】期末必备&#xff01;8小时速成信号与系统&#xff01;_哔哩哔哩_bilibili 精通&#xff1a;2022浙江大学信号与系统&#xff08;含配…...

第32次CCF计算机软件能力认证-2-因子化简

因子化简 刷新 时间限制&#xff1a; 2.0 秒 空间限制&#xff1a; 512 MiB 下载题目目录&#xff08;样例文件&#xff09; 题目背景 质数&#xff08;又称“素数”&#xff09;是指在大于 11 的自然数中&#xff0c;除了 11 和它本身以外不再有其他因数的自然数。 题…...

mac笔记本如何快捷键截图后自动复制到粘贴板

前提&#xff1a;之前只会进行部分区域截图操作&#xff08;commandshift4&#xff09;操作&#xff0c;截图后发现未自动保存在剪贴板&#xff0c;还要进行一步手动复制到剪贴板的操作。 mac笔记本如何快捷键截图后自动复制到粘贴板 截取 Mac 屏幕的一部分并将其自动复制到剪…...

高考加油!UI界面生成器!

这个高考助力标语生成器具有以下特点&#xff1a; 视觉设计&#xff1a;采用了蓝色为主色调&#xff0c;搭配渐变背景和圆形装饰元素&#xff0c;营造出宁静而充满希望的氛围&#xff0c;非常适合高考主题。 标语生成&#xff1a;内置了超过 100 条精心挑选的高考加油标语&a…...

window ollama部署模型

注意去官网下载ollama,这个win和linux差别不大,win下载exe,linux用官网提供的curl命令 模型下载表:deepseek-r1 使用命令:Ollama API 交互 | 菜鸟教程 示例: 1.查看已加载模型: 2.文本生成接口 curl -X POST http://localhost:11434/v1/completions -H "Conte…...

用mediamtx搭建简易rtmp,rtsp视频服务器

简述&#xff1a; 平常测试的时候搭建rtmp服务器很麻烦&#xff0c;这个mediamtx服务器&#xff0c;只要下载就能运行&#xff0c;不用安装、编译、配置等&#xff0c;简单易用、ffmpeg推流、vlc拉流 基础环境&#xff1a; vmware17&#xff0c;centos10 64位&#xff0c;wi…...

ubuntu安装devkitPro

建议开个魔法 wget https://apt.devkitpro.org/install-devkitpro-pacman chmod x ./install-devkitpro-pacman sudo ./install-devkitpro-pacman&#xff08;下面这句如果报错也没事&#xff09; sudo ln -s /proc/self/mounts /etc/mtab往~.bashrc添加 export DEVKITPRO/o…...

Linux(10)——第二个小程序(自制shell)

目录 ​编辑 一、引言与动机 &#x1f4dd;背景 &#x1f4dd;主要内容概括 二、全局数据 三、环境变量的初始化 ✅ 代码实现 四、构造动态提示符 ✅ 打印提示符函数 ✅ 提示符生成函数 ✅获取用户名函数 ✅获取主机名函数 ✅获取当前目录名函数 五、命令的读取与…...

github actions入门指南

GitHub Actions 是 GitHub 提供的持续集成和持续交付&#xff08;CI/CD&#xff09;平台&#xff0c;允许开发者自动化软件工作流程&#xff08;如构建、测试、部署&#xff09;。以下是详细介绍&#xff1a; 一、核心概念 Workflow&#xff08;工作流程&#xff09; 持续集成的…...

代码随想录算法训练营 Day59 图论Ⅸ dijkstra优化版 bellman_ford

图论 题目 47. 参加科学大会&#xff08;第六期模拟笔试&#xff09; 改进版本的 dijkstra 算法&#xff08;堆优化版本&#xff09; 朴素版本的 dijkstra 算法解法的时间复杂度为 O ( n 2 ) O(n^2) O(n2) 时间复杂度与 n 有关系&#xff0c;与边无关系 类似于 prim 对应点多…...

HTML实战:响应式个人资料页面

我将创建一个现代化的响应式个人资料页面,展示HTML在实际应用中的强大功能。这个页面将包含多个实战元素:导航栏、个人简介、技能展示、作品集和联系表单。 设计思路 使用Flexbox和Grid布局实现响应式设计 添加CSS过渡效果增强交互体验 实现深色/浅色模式切换功能 创建悬停动…...

Mac电脑上本地安装 MySQL并配置开启自启完整流程

文章目录 一、mysql安装1.1 使用 Homebrew 安装&#xff08;推荐&#xff09;1.2 手动下载 MySQL 社区版1.3 常见问题1.4 图形化管理工具&#xff08;可选&#xff09; 二、Mac 上配置 MySQL 开机自动启动2.1 使用 launchd 系统服务&#xff08;原生支持&#xff09;2.2 通过 H…...

JavaSE:面向对象进阶之内部类(Inner Class)

JavaSE 面向对象进阶之内部类&#xff08;Inner Class&#xff09; 一、内部类的核心概念 内部类是定义在另一个类内部的类&#xff0c;它与外部类存在紧密的逻辑关联&#xff0c;主要作用&#xff1a; 封装细节&#xff1a;隐藏实现细节&#xff0c;对外提供简洁接口。访问…...

【HW系列】—安全设备介绍(开源蜜罐的安装以及使用指南)

文章目录 蜜罐1. 什么是蜜罐&#xff1f;2. 开源蜜罐搭建与使用3. HFish 开源蜜罐详解安装步骤使用指南关闭方法 总结 蜜罐 1. 什么是蜜罐&#xff1f; 蜜罐&#xff08;Honeypot&#xff09;是一种主动防御技术&#xff0c;通过模拟存在漏洞的系统或服务&#xff08;如数据库…...

汽车总线分析总结(CAN、LIN、FlexRay、MOST、车载以太网)

目录 一、汽车总线技术概述 二、主流汽车总线技术对比分析 1. CAN总线&#xff08;Controller Area Network&#xff09; 2. LIN总线&#xff08;Local Interconnect Network&#xff09; 3. FlexRay总线 4. MOST总线&#xff08;Media Oriented Systems Transport&#x…...

MyBatisPlus--条件构造器及自定义SQL详解

条件构造器 在前面学习快速入门的时候&#xff0c;练习的增删改查都是基于id去执行的&#xff0c;但是在实际开发业务中&#xff0c;增删改查的条件往往是比较复杂的&#xff0c;因此MyBatisPlus就提供了一个条件构造器来帮助构造复杂的条件。 MyBatisPlus支持各种复杂的wher…...

OVD开放词汇检测 Detic 训练COCO数据集实践

0、引言 纯视觉检测当前研究基本比较饱和&#xff0c;继续创新提升空间很小&#xff0c;除非在CNN和transformer上提出更强基础建模方式。和文本结合是当前的一大趋势&#xff0c;也是计算机视觉和自然语言处理结合的未来趋势&#xff0c;目前和文本结合的目标检测工作还是有很…...

docker、ctr、crictl命令简介与使用

概述 在使用k3s过程中&#xff0c;经常需要使用ctr和crictl两个命令&#xff0c;本文记录一下。 ctr 类似docker命令是docker-shim容器运行时的客户端工具&#xff0c;ctr是Containerd的客户端工具。一个简单的CLI接口&#xff0c;用作Containerd本身的一些调试用途&#xf…...

WEB安全--SQL注入--bypass技巧2

继之前文章的补充&#xff1a; WEB安全--SQL注入--bypass技巧_sql注入过滤空格-CSDN博客 Q1&#xff1a;发现sql注入的时间盲注时&#xff0c;如果时间盲注的函数都被过滤了&#xff0c;怎么办&#xff1f; 除了找其他函数替换、编码等方式&#xff0c;还有以下方式绕过&…...

【强化学习哲学 Day 1】Q-Learning - 在不确定中寻找确定

&#x1f3ad; 故事&#xff1a;那些选择的时刻 你还记得那些站在十字路口的时刻吗&#xff1f; 也许是刚进实验室&#xff0c;面对满墙的研究方向海报&#xff0c;不知道哪条路通向你想要的未来&#xff1b;也许是第一份工作的选择&#xff0c;大厂的螺丝钉还是小公司的多面…...

WEB3——什么是ABI

怎么获得ABI&#xff1f; 在编译完合约后&#xff0c;可以在左边下面点击复制ABI ABI&#xff08;Application Binary Interface&#xff0c;应用二进制接口&#xff09;是用来让前端或服务端 JavaScript 代码与智能合约进行交互的桥梁&#xff0c;它描述了合约的函数、事件和…...

嵌入式软件--stm32 DAY 8.5 基础复习总结

1.时钟树 在数据手册里面&#xff0c;有一张密密麻麻的图&#xff0c;正是时钟系统里的时钟树。 对于时钟&#xff0c;我们注意有两点。一个是系统时钟SYSCLK,一个是依赖外部晶振生成的RTC. RTC以外部低速晶振作为时钟源或者外部高速晶振128分频后作为时钟源&#xff0c;又或者…...

MMRL: Multi-Modal Representation Learning for Vision-Language Models(多模态表示学习)

摘要 预训练的VLMs,对于跨任务的迁移学习至关重要&#xff0c;然而&#xff0c;在few-shot数据集上微调会导致过拟合&#xff0c;降低在新任务上的性能。为解决这个问题&#xff0c;提出一种新的多模态表征学习框架&#xff08;MMRL&#xff09;,该框架引入了一个共享、可学习…...

贪心算法求解汽车加油问题

一、问题描述 一辆汽车加满油后可以行驶 n km。在前往目的地的途中&#xff0c;有多个加油站。我们的目标是设计一个有效的算法&#xff0c;确定汽车应该在哪些加油站停靠加油&#xff0c;以使得沿途的加油次数最少。 二、输入输出形式 算法的输入包括两部分&#xff1a;第一…...

JVM Full GC 频繁问题排查、优化及解决方案

引言 在Java应用程序中&#xff0c;JVM&#xff08;Java虚拟机&#xff09;通过垃圾回收机制自动管理内存&#xff0c;确保不再使用的对象能够被及时清理和释放。虽然垃圾回收在大多数情况下运行顺利&#xff0c;但当Full GC频繁发生时&#xff0c;它会严重影响应用性能&#x…...

rsync服务的搭建

目录 一、rsync介绍 rsync的安装 二、rsync的语法 三、rsync命令使用 1. 本机同步 2. 远程同步 四、rsync作为服务使用 1、尝试启动rsync程序 2、rsync的配置文件介绍 注意事项&#xff1a; 3. rsyncinotify实时同步 3.依赖服务托管xinetd&#xff08;CentOS 6中rs…...