Netty编解码器

目录

1、概念

2、Netty提供的编解码器类型

2.1 解码器

2.1.1 ByteToMessageDecoder

2.1.2 ReplayingDecoder

2.1.3 MessageToMessageDecoder

2.2 编码器

2.2.1 MessageToByteEncoder

2.2.2 MessageToMessageEncoder

2.3 编解码器

2.3.1 ByteToMessageCodec

2.3.2 MessageToMessageCodec

2.3.3 CombinedChannelDuplexHandler

3、使用注意事项

4、示例:一个简单的字符串编解码器


1、概念

Netty 的编解码器是其网络编程框架中的核心组件,负责处理网络通信中最基本也最关键的字节与消息对象之间的相互转换

核心概念:

  • 解码器: 将接收到的原始字节流 (ByteBuf) 转换成有意义的应用程序级消息对象。这个过程发生在数据入站时(从网络到应用)。

  • 编码器: 将应用程序级的消息对象转换成字节流 (ByteBuf),以便通过网络发送。这个过程发生在数据出站时(从应用到网络)。

  • 编解码器: 同时实现了编码器和解码器功能的组件。

解决的问题:

  • 解码: 解决如何从连续的、可能被 TCP 粘包/拆包的字节流中,正确地切割、识别并还原出发送方发送的一个个完整消息。

  • 编码: 解决如何将结构化的消息对象高效地、符合协议规范地序列化成字节序列,以便发送。

2、Netty提供的编解码器类型

2.1 解码器

Netty 的解码器都实现了 ChannelInboundHandler 接口,处理入站数据。需要将解码器放在ChannelPipeline中。常见的抽象基类和实现:

2.1.1 ByteToMessageDecoder

  • 功能: 将入站的 ByteBuf 累积到内部的缓冲区中,直到有足够的数据可以解码成一个完整的消息对象。需要检查缓冲区是否有足够的字节。

  • 关键方法: decode(ChannelHandlerContext ctx, ByteBuf in, List out)

    • in: 当前累积的、可读的输入 ByteBuf

    • out: 用于存放解码成功的完整消息对象的列表。每添加一个对象,就表示成功解码了一条消息。

  • 职责: 开发者继承此类,实现 decode 方法:

    1. 检查 in 中是否有足够的数据构成一个完整消息。

    2. 如果足够,从 in 中读取数据,构造出消息对象。

    3. 将构造好的消息对象添加到 out 列表中。

    4. 重复步骤 1-3 直到 in 中不再有足够的数据构成完整消息。

  • 内部缓冲: 它会自动管理累积的字节,处理粘包问题。当 in 被读取后,已读取的字节会被丢弃,保留未读取的字节供下次解码。

  • 示例: LineBasedFrameDecoder (基于换行符拆包), FixedLengthFrameDecoder (固定长度拆包), LengthFieldBasedFrameDecoder (基于长度字段拆包 - 极其重要和常用)。

2.1.2 ReplayingDecoder

  • 特点: 简化了解码逻辑。它假设在调用 decode 方法时,ByteBuf in 中总是有足够的数据可供读取下一个需要的字段。如果数据不足,它会抛出特殊异常(由框架捕获),并等待更多数据到来后重试解码。

  • 优点: 代码更简洁,不需要手动检查每个字段是否有足够数据。

  • 缺点: 性能可能略低于 ByteToMessageDecoder (因为需要异常机制),且 in 的某些操作受限(如 readableBytes()),不是所有的ByteBuff都支持。

  • 适用: 协议简单或对极致性能要求不苛刻的场景。

2.1.3 MessageToMessageDecoder

  • 核心: 将一种消息对象解码成另一种消息对象

  • 功能: 用于消息处理管道中的消息转换阶段。输入和输出都是对象,不再是原始的 ByteBuf

  • 关键方法: decode(ChannelHandlerContext ctx, I msg, List out)

    • msg: 输入的上一个 Handler 传递下来的消息对象(类型 I)。

    • out: 存放转换后的消息对象(类型 O)的列表。

  • 示例: 将 ByteBuf 解码成的 String 对象再解码成自定义的 LoginRequest 对象;将 Protobuf 的 ByteBuf 解码成生成的 MessageLite 对象。

2.2 编码器

Netty 的编码器都实现了 ChannelOutboundHandler 接口,处理出站数据。常见的抽象基类和实现:

2.2.1 MessageToByteEncoder

  • 功能: 将应用程序的消息对象编码成字节流 (ByteBuf)。

  • 关键方法: encode(ChannelHandlerContext ctx, I msg, ByteBuf out)

    • msg: 要编码的消息对象(类型 I)。

    • out: 用于写入编码后字节的目标 ByteBuf

  • 职责: 开发者继承此类,实现 encode 方法:

    1. 将 msg 对象包含的信息(如字段值)按照协议规范写入到 out ByteBuf 中。

    2. 通常需要处理长度字段(如果需要)、序列化等。

  • 示例: 将 String 编码成 ByteBuf (通常使用 ctx.alloc().buffer() 创建并写入字节),将自定义的 LoginResponse 对象编码成协议规定的字节格式。

2.2.2 MessageToMessageEncoder

  • 核心: 将一种消息对象编码成另一种消息对象

  • 功能: 用于消息处理管道中的消息转换阶段,输出对象通常最终会被下游的 MessageToByteEncoder 处理。

  • 关键方法: encode(ChannelHandlerContext ctx, I msg, List out)

    • msg: 要转换的消息对象(类型 I)。

    • out: 存放转换后的消息对象(类型 O)的列表。

  • 示例: 将自定义的 LoginResponse 对象转换成 Protobuf 生成的 MessageLite 对象;将 String 转换成包含该字符串的 TextWebSocketFrame

2.3 编解码器

编码解码器: 同时具有编码与解码功能,特点同时实现了ChannelInboundHandler和ChannelOutboundHandler接口,因此在数据输入和输出时都能进行处理。Netty提供提供了一个ChannelDuplexHandler适配器类,编码解码器的抽象基类。

2.3.1 ByteToMessageCodec

结合了 ByteToMessageDecoder 和 MessageToByteEncoder

2.3.2 MessageToMessageCodec

结合了 MessageToMessageDecoder 和 MessageToMessageEncoder

2.3.3 CombinedChannelDuplexHandler

一个更灵活的通用组合方式,允许你将任意一个解码器 (ChannelInboundHandler) 和任意一个编码器 (ChannelOutboundHandler) 组合在一起,作为一个编解码器添加到 pipeline 中。这是推荐的方式来组合独立的编解码逻辑,避免多重继承可能带来的问题。

public class MyCodec extends CombinedChannelDuplexHandler<MyDecoder, MyEncoder> {public MyCodec() {super(new MyDecoder(), new MyEncoder());}
}

3、使用注意事项

  • 处理 TCP 粘包/拆包: 这是解码器的核心职责之一。务必使用 ByteToMessageDecoder 或其子类(如 LengthFieldBasedFrameDecoder)来自动累积和拆包。不要试图在 channelRead 中直接处理原始 ByteBuf 来解析完整消息

  • 使用 LengthFieldBasedFrameDecoder: 对于自定义二进制协议,这是最常用、最可靠的拆包解码器。它通过协议头中明确指定的长度字段来确定一个完整帧的边界,完美解决粘包拆包问题。

  • 资源管理: ByteBuf 是 Netty 管理的内存。在编码器 encode 方法中创建的 ByteBuf,Netty 框架会在写入完成后负责释放。在解码器 decode 方法中,不要释放传入的 ByteBuf inByteToMessageDecoder 会自动管理其生命周期。处理 out 列表中的对象时,确保它们被正确传递下去或被释放(如果需要)。遵循 Netty 的引用计数规则。

  • 可重用性: 编解码器通常是线程安全的和无状态的,可以被多个 Channel 共享(添加时使用 @Sharable 注解并确保确实无状态)。

  • Pipeline 顺序:

    • 解码器 (ChannelInboundHandler) 应该添加在靠近 SocketChannel 的一端(Pipeline 的前端)。

    • 编码器 (ChannelOutboundHandler) 应该添加在靠近业务逻辑 Handler 的一端(Pipeline 的后端)。

    • 一个典型的 Pipeline 顺序可能是:LengthFieldBasedFrameDecoder -> MyProtocolDecoder (ByteToMessageDecoder) -> MyBusinessLogicHandler -> MyProtocolEncoder (MessageToByteEncoder) -> ... (其他出站处理器如日志、加密)。

  • 利用现有实现: 优先使用 Netty 内置的编解码器(如 HTTP、WebSocket、Protobuf、Marshalling、Base64 等),它们经过充分测试和优化。

  • 性能: 编解码通常是性能关键路径。避免在编解码方法中进行阻塞操作或创建过多临时对象。考虑使用对象池(如 Recycler)复用消息对象。

4、示例:一个简单的字符串编解码器

// 编码器 (出站:Object -> ByteBuf)
@Sharable
public class StringEncoder extends MessageToByteEncoder<String> {@Overrideprotected void encode(ChannelHandlerContext ctx, String msg, ByteBuf out) throws Exception {// 将字符串写入ByteBuf (使用UTF-8编码)out.writeCharSequence(msg, StandardCharsets.UTF_8);}
}// 解码器 (入站:ByteBuf -> String)
@Sharable
public class StringDecoder extends ByteToMessageDecoder {@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {// 简单示例:假设每个ByteBuf都包含一个完整的UTF-8字符串// 实际中需要处理粘包拆包!这里仅作演示。out.add(in.toString(StandardCharsets.UTF_8));in.readerIndex(in.writerIndex()); // 标记所有字节已读 (仅用于此简单示例)}
}// 或者使用更健壮的 LineBasedFrameDecoder + StringDecoder 组合来处理行分隔的消息
public class ServerInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline p = ch.pipeline();// 入站 Pipeline (从网络到应用)p.addLast(new LineBasedFrameDecoder(1024)); // 按行拆包,最大行长度1024p.addLast(new StringDecoder(StandardCharsets.UTF_8)); // 将一行字节转成Stringp.addLast(new MyStringHandler()); // 业务逻辑处理器,处理String对象// 出站 Pipeline (从应用到网络)p.addLast(new StringEncoder(StandardCharsets.UTF_8)); // 将String转成字节}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/89072.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/89072.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

企业内部安全组网技术解析:安全通道选型、零信任架构与数据合规加密防护

一、引言&#xff1a;企业内部安全组网的重要性 随着企业数字化转型的深入以及远程办公需求的增加&#xff0c;企业内部异地组网逐渐成为企业信息技术部门关注的重要话题。如何在合规合法的前提下&#xff0c;保障企业内部网络连接的安全性、稳定性&#xff0c;并有效保护企业…

Windows 4625日志类别解析:未成功的账户登录事件

Windows 4625日志类别解析&#xff1a;未成功的账户登录事件 什么是Windows 4625日志&#xff1f; Windows 4625日志属于安全日志&#xff08;Security Log&#xff09; 的一部分&#xff0c;记录系统中未成功的账户登录尝试&#xff08;Failed Logon&#xff09;。它是追踪非…

3D看房实现房屋的切换

作为3D看房的补充&#xff0c;在这里&#xff0c;我们讲一下如何实现房屋的切换&#xff0c;我这里提供两种思路&#xff0c; 切换贴图&#xff0c;切换场景&#xff0c; 接下我们按照较复杂的场景切换来讲&#xff0c;切换贴图也就水到渠成&#xff1a; 初始化场景&#xf…

[Android]ANR的线程

ANR的原理是进行了超时告警&#xff0c;在执行一个需要被监控的任务时&#xff0c;注册一个超时提醒&#xff0c;如果很快执行好了&#xff0c;删除这个提醒&#xff0c;如果超时&#xff0c;这个提醒就被触发&#xff0c;这个超时处理是通过handler方式来调用的&#xff0c;这…

RLVR来做Agent任务能力增强训练

和上一篇其实有点承接 上一篇的争论其实是因为要优化agent的任务规划和实现能力的 所以有了self-learning之争 当我们说Self-learning&#xff0c;其实是在说什么&#xff1f; 其实上一篇最后时候提了一点拿RLVR来做agent的任务提升 正好今天看到了一篇应景的论文&#xf…

如何运营一个开源项目并取得较大影响力?

开源不仅是主要的软件开发方法论&#xff0c;还是助力快速创新、分散协作、 生态系统建设和职业发展的卓越战略。如今&#xff0c;无论在哪里&#xff0c;都离不开与 开源的互动。开源存在于你的手机、汽车和冰箱中&#xff0c;它使你最喜欢的节 目或电影的制作和发行成为可能&…

华为高斯数据库的数据类型

华为高斯数据库的数据类型 国产数据库华为高斯的GaussDB的数据类型 华为高斯数据库的数据类型✅ 一、数值类型&#xff08;Numeric Types&#xff09;✅ 二、字符类型&#xff08;Character Types&#xff09;✅ 三、布尔类型&#xff08;Boolean Type&#xff09;✅ 四、日期和…

生物实验室安全、化学品安全

zhihu.com/column/c_1922752541369800632 Docs 目录 第七章 7.1 实验室生物安全等级 7.1.1 生物安全基本概念 7.1.2 生物的危害等级 7.1.2.1 国内生物危害等级 7.1.3 实验室生物安全防护水平分级 7.2 实验室生物安全控制 7.2.1 实验室生物仪器设备安全控制 7.2.1.1 生…

【QT】第一个QT程序 || 对象树 || 编码时的注意事项

一、编写第一个 Qt 程序 1. 开发环境搭建 安装 Qt Creator&#xff08;推荐使用官方在线安装器&#xff09;安装 Qt 库&#xff08;如 Qt 5.15.2 或 Qt 6.x&#xff09;配置编译器&#xff08;MinGW / MSVC / GCC&#xff09; 2. 创建一个简单的 Qt GUI 应用程序 打开 Qt C…

多服务器IP白名单配置(使用redis stream实现)

应用背景 现在我有一个管理平台,可以通过代理连接到内网网站,但是这个代理服务器没有设置密码,所以需要IP白名单让指定用户才可以使用代理。 添加白名单流程图 流程描述: 登录管理平台成功后,管理平台的后台将这个登录的IP地址添加到redis,并设置过期时间为24小时redis…

Vue 3 Teleport 特性

目录 基本用法​ 搭配组件使用​ 禁用 Teleport​ 多个 Teleport 共享目标​ 延迟解析的 Teleport ​ 总结 <Teleport> 是一个内置组件&#xff0c;它可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。 基本用法​ 有时我们可能会遇到这…

常用指令合集(DOS/Linux/git/Maven等)

文章目录 常用指令收集vmware 虚拟机联网设置ubuntu 常见问题设置apt 相关指令&#xff1a;gcc 编译相关指令 sqlite3VSCode 快捷键&#xff1a;收索引擎技巧&#xff08;google&#xff09;Intelideashell--LinxvimgitDOS:mavendockerkubectl 指令nginx配置redis-clientMySQLl…

ABP VNext + MassTransit:构建分布式事务与异步消息协作

ABP VNext MassTransit&#xff1a;构建分布式事务与异步消息协作 &#x1f680; &#x1f4da; 目录 ABP VNext MassTransit&#xff1a;构建分布式事务与异步消息协作 &#x1f680;&#x1f4da; 1. 背景与动机&#x1f6e0;️ 2. 环境与依赖&#x1f527; 3. 在 ABP 模块…

语义网技术

用通俗语言说语义网技术&#xff0c;以及它和现在互联网的关系 一、语义网技术&#xff1a;让网络“听懂人话”的智能升级 现有互联网就像一本巨大的“图文报纸”&#xff1a;我们人类看文章、图片能轻松理解意思&#xff0c;但计算机只能识别文字符号&#xff0c;不知道“苹…

pytorch学习—4.反向传播(用pytorch算梯度)

2. 线性模型 3.梯度下降算法 4.反向传播_哔哩哔哩_bilibili 4.1 代码复现 import torch import matplotlib.pyplot as pltx_data=[1.0,2.0,3.0] y_data=[2.0,4.0,6.0]#这里创建了一个PyTorch张量w,初始值为1.0,并且设置requires_grad=True, #这意味着在计算过程中,PyTo…

7类茶叶嫩芽图像分类数据集

在茶叶育种、溯源管理与自动采摘等智能农业场景中&#xff0c;茶树品种的识别与分类是一项关键任务。不同茶叶品种在嫩芽期表现出显著的形态差异&#xff0c;例如颜色、叶缘结构、芽头密度等。因此&#xff0c;基于图像的茶叶品种分类不仅具备实际应用价值&#xff0c;也为农业…

【Elasticsearch】Linux环境下安装Elasticsearch

一&#xff0c;前言 Elasticsearch&#xff08;简称 ES&#xff09;是一个基于 ​​Apache Lucene​​ 构建的开源分布式搜索与分析引擎。它支持​​实时数据处理​​&#xff0c;提供近实时的全文搜索能力&#xff0c;并通过 ​​JSON 格式的 RESTful API​​ 实现数据索引与检…

【数据结构--树于哨兵查找-1】

查找 从前到后- 线性查找 -就是顺序查找. 哨兵法查找–节省每次都要判断是否越界的这一步骤利于节省开销&#xff0c;从而提升效率。 参考我的程序 #include <stdio.h> #include <stdlib.h> #include <time.h> #include <stdbool.h>#define SIZE …

MyBatis修改(update)操作

1. 三步法口诀 “接口收对象&#xff0c;SQL全赋值&#xff0c;主键定目标” 2. 详细记忆点 | 步骤 | 口诀 | 说明与示例 | |--------------|----------------|----------------------------------------------------------------------------| | 1. 写接口 | “接口收对象…

Spring Boot 入门学习

一、 Web应用开发概述 什么是Web应用 1. Web应用 &#xff08;Web Application&#xff09;是一种运行在Web服务器上的软件程序&#xff0c;由用户通过Web浏览器进行访问和交互。 2.Web应用与传统的桌面应用不同&#xff0c;它不需要在个人计算机上安装特定的软件&#xff0…