Netty ByteToMessageDecoder 中 ByteBuf 的readerIndex 详解 📅 发布时间:2026/7/17 5:14:27 👁️ 浏览次数: 在Netty的ByteToMessageDecoder中ByteBuf扮演了“原始数据的临时容器”和“解码操作的对象”的双重角色。它既缓存了不完整的网络数据包也是进行解码操作时直接操作的对象。一. ByteBuf的内部结构二. 影响 readerIndex 的操作(1) 前移 readerIndex消耗数据byteBuf.readByte() // 1byteBuf.readShort() // 2byteBuf.readInt() // 4byteBuf.readLong() // 8byteBuf.readBytes(dst) // dst.lengthbyteBuf.readBytes(dst, 0, 5) // 5byteBuf.skipBytes(n) // nbyteBuf.readCharSequence(n, charset) // n(2) 不改变 readerIndexbyteBuf.getByte(index) // 绝对读取不改 indexbyteBuf.getInt(index) // 绝对读取不改 indexbyteBuf.getBytes(index, dst) // 绝对读取不改 indexbyteBuf.readableBytes() // 只查询byteBuf.capacity() // 只查询byteBuf.duplicate() // 共享数据独立 indexbyteBuf.slice() // 共享数据独立 indexbyteBuf.copy() // 深拷贝完全独立(3) 直接设置 readerIndexbyteBuf.readerIndex(0) // 直接设置为 0byteBuf.resetReaderIndex() // 回退到上次 markReaderIndex() 的位置byteBuf.markReaderIndex() // 记录当前 readerIndex 位置不改值(4) mark / reset 机制byteBuf.markReaderIndex(); // 记住当前位置比如 0byteBuf.readByte(); // readerIndex: 0→1byteBuf.readByte(); // readerIndex: 1→2byteBuf.resetReaderIndex(); // 回到 0必须先 mark否则行为不确定没有 mark 就 reset 的行为- Netty 4.x 默认回退到 0AbstractByteBuf 的默认 mark 是 0- 但这不是规范行为依赖默认值是坏习惯三. ByteToMessageDecoder 中的规范用法ByteToMessageDecoder 的 decode() 方法有严格约定规则 1添加了消息到 list必须消费字节// ❌ 错误list.add() 了但 readerIndex 没动 → did not read anything but decoded a messageprotected void decode(ctx, byteBuf, list) {byteBuf.resetReaderIndex(); // readerIndex 回到 0list.add(byteBuf); // 加了消息但没消费字节}// ✅ 正确添加消息后标记字节已消费protected void decode(ctx, byteBuf, list) {ByteBuf data byteBuf.retainedDuplicate();list.add(data);byteBuf.skipBytes(byteBuf.readableBytes()); // 标记已消费}规则 2不处理就不要动 readerIndex直接 return// ✅ 正确数据不够等下次protected void decode(ctx, byteBuf, list) {if (byteBuf.readableBytes() 2) {return; // 不读字节不改 readerIndex}...}规则 3不要把内部 ByteBuf 直接传给下游// ❌ 错误传内部 buffer下游释放后 decoder 再释放 → 双重释放channelHandlerContext.fireChannelRead(byteBuf);// ✅ 正确用 retainedDuplicate() 创建副本ByteBuf data byteBuf.retainedDuplicate();list.add(data);byteBuf.skipBytes(byteBuf.readableBytes());规则 4mark 和 reset 必须配对// ❌ 错误没有 mark 就 resetbyteBuf.readByte();byteBuf.resetReaderIndex(); // 行为不确定// ✅ 正确先 mark 再 resetbyteBuf.markReaderIndex();byteBuf.readByte();byteBuf.resetReaderIndex();总结速查表四. ByteBuf读取和消费有的区别● 好问题。在大多数场景下读取 消费。但在 Netty 中它们有区别读取 ≠ 消费 的场景1. 读了但退回 — 不算消费byteBuf.markReaderIndex(); // readerIndex 0记住位置byte b byteBuf.readByte(); // readerIndex 1读了byteBuf.resetReaderIndex(); // readerIndex 0退回去// ByteToMessageDecoder 视角readerIndex 没动 → 没消费任何字节读了但退回去等于没读。2. 窥探但不移动 — 不算消费byte b byteBuf.getByte(0); // 看了一眼readerIndex 还是 03. 读了但传给别人 — 谁消费byte[] data new byte[byteBuf.readableBytes()];byteBuf.readBytes(data); // readerIndex 到底自己消费了channelHandlerContext.fireChannelRead(byteBuf); // 传空的给别人没意义// vsByteBuf copy byteBuf.retainedDuplicate(); // 副本readerIndex 0list.add(copy); // 副本给下游消费byteBuf.skipBytes(byteBuf.readableBytes()); // 原 buffer 标记已消费从 ByteToMessageDecoder 的视角理解ByteToMessageDecoder 只看一件事decode() 调用前后readerIndex 有没有移动。// 情况 AreaderIndex 移动了 → 消费了readerIndex before: 0decode() { byteBuf.readByte(); } // readerIndex: 0→1readerIndex after: 1→ 消耗了 1 字节 ✓// 情况 BreaderIndex 没动 → 没消费readerIndex before: 0decode() { byteBuf.markReaderIndex(); byteBuf.readByte(); byteBuf.resetReaderIndex(); }readerIndex after: 0→ 消耗了 0 字节 ✗// 情况 CreaderIndex 没动但 list 有消息 → 报错readerIndex before: 0decode() { byteBuf.resetReaderIndex(); list.add(byteBuf); }readerIndex after: 0→ did not read anything but decoded a message ❌一句话总结- 读取访问数据的行为readByte()、getByte() 都算- 消费readerIndex 净前移了多少mark read reset 读了但没消费就像你翻了一下书但合回去说我没看。
RISC-V与ARM架构单板机Redis性能对比测试 1. 昉星光 2与树莓派4B硬件对比作为一名长期从事嵌入式开发的工程师,我最近拿到了昉星光 2这块基于RISC-V架构的单板计算机。在开始Redis测试前,有必要先了解它的硬件特性以及与树莓派4B的关键差异。1.1 昉星光 2硬件解析昉星光 2搭载的是赛昉科技JH7110… 2026/7/17 5:12:27
OpenStack Neutron软件包安装顺序与网络架构关系解析 1. 这不是“装几个包”那么简单:Neutron软件包安装背后的网络架构决策很多人看到“安装 OpenStack Neutron 相关软件包”这个标题,第一反应是翻出yum install或apt-get install的命令列表,敲完回车就以为万事大吉。我当年在第一个生产环境部署… 2026/7/17 5:08:25
C++动态数组实现:从内存管理到性能优化的深度实践 1. 项目概述:为什么我们需要自己造一个动态数组?在C的世界里,std::vector几乎是每个开发者都会用到的标准库容器,它稳定、高效,封装了所有动态数组的复杂细节。那么,为什么我们还要“重复造轮子”ÿ… 2026/7/17 5:08:25
Python数据分析实战:从环境搭建到电商用户行为分析 1. 为什么选择Python进行数据分析?Python已经成为数据分析领域的事实标准语言,这绝非偶然。作为一个从2012年开始使用Python处理数据的从业者,我见证了Python在数据科学领域的崛起过程。与其他语言相比,Python最大的优势在于其完整… 2026/7/17 6:28:53
【安心陪诊 Agent】AI 对话设计:为什么安心陪诊不能像机器人一样回复 应用名称:安心陪诊 Agent 统一合集:安心陪诊 Agent|HarmonyOS 高校创新赛 关键词标签:harmonyos / AI Agent / 医疗陪诊 AI 对话设计:为什么安心陪诊不能像机器人一样回复 摘要:从语气、句长、顺序、边界和… 2026/7/17 6:26:52
同城代驾小程序开发公司排名,用户一键下单接口开发实操 同城代驾小程序开发公司排名,用户一键下单接口开发实操同城代驾小程序的用户核心操作集中在一键下单功能,接口的稳定性、容错性、响应速度直接决定用户下单体验与订单转化率。市面上多数低端模板化代驾小程序,一键下单接口开发逻辑简陋&#… 2026/7/17 6:26:52
RMBG-2.0发丝级AI抠图:技术原理与工程实践指南 1. RMBG-2.0技术背景与核心优势RMBG-2.0是当前AI图像处理领域最具突破性的背景移除工具之一,其核心价值在于实现了传统算法难以企及的发丝级抠图精度。与早期版本相比,2.0版本通过改进的神经网络架构和训练策略,在复杂边缘处理上取得了显著进… 2026/7/17 6:24:52
【2014-01-26】jython学习笔记:打印模块信息 [历史归档] 本文原发布于 cstriker1407.info 个人博客,内容为历史存档,仅供参考。 发布时间: 2014-01-26 | 标题:jython学习笔记:打印模块信息 | 分类: 编程 / python &&… 2026/7/17 6:24:52
离线截图OCR识别工具6.26更新:新增表格识别,PDF仅美化标题 在日常工作与学习中,我们经常需要从截图、PDF文档中提取文字信息。手动输入不仅效率低下,还容易出错。离线OCR(光学字符识别)工具的出现,为我们提供了高效、准确的解决方案。近期,一款备受好评的离线截图OC… 2026/7/17 6:20:50
【WPS AI表格避坑白皮书】:实测发现87%用户正在误用AI函数——这5个致命错误导致结果偏差超42% 更多请点击: https://intelliparadigm.com 第一章:WPS AI表格的核心能力与适用边界 WPS AI表格将大语言模型能力深度集成于电子表格环境中,实现从自然语言指令到结构化数据操作的端到端转化。其核心并非替代传统公式或宏编程,而是… 2026/7/17 0:00:08
Cursor终端插件生态避坑指南:23个实测低效插件黑名单,附3个自研轻量替代方案 更多请点击: https://intelliparadigm.com 第一章:Cursor终端插件生态避坑指南概览 Cursor 作为基于 VS Code 内核构建的 AI 原生编辑器,其终端插件生态虽活跃,但存在兼容性断层、权限策略突变与调试链路断裂等典型风险。开发者常… 2026/7/17 0:00:08
ChatGPT写作提示词效率革命:单条提示词响应质量提升3.8倍的关键变量(附可复用提示词矩阵表) 更多请点击: https://codechina.net 第一章:ChatGPT写作提示词效率革命:单条提示词响应质量提升3.8倍的关键变量(附可复用提示词矩阵表) 提示词工程已从经验试错迈入变量驱动的科学阶段。实证研究表明,影响… 2026/7/17 0:00:08
Git reset 与 revert 深度对比:5个关键差异与 3 种典型应用场景 Git Reset 与 Revert 深度对比:5个关键差异与3种典型应用场景在团队协作开发中,代码版本管理如同行走钢丝——一步失误可能导致整个项目陷入混乱。作为Git进阶用户,你是否曾在深夜面对错误的提交束手无策?是否在强制推送后收到同事… 2026/7/17 0:28:39
GitHub 学生包申请避坑:5个常见失败原因与开发者工具调试方案 GitHub 学生包申请技术排障指南:5个高频失败场景与开发者工具实战方案第一次尝试申请GitHub学生包时,我盯着屏幕上那个不断转圈的加载动画整整15分钟,最终只等来了一行冰冷的错误提示。这可能是许多开发者共同的经历——明明按照教程操作&… 2026/7/17 6:02:24
冒烟测试用例设计规范:5%-10%覆盖率下的3类核心场景与执行标准 冒烟测试用例设计的黄金法则:5%-10%覆盖率下的精准筛选策略在快节奏的敏捷开发环境中,冒烟测试作为质量保障的第一道防线,其重要性不言而喻。当测试资源有限而时间紧迫时,如何从海量测试用例中精准筛选出那关键的5%-10%࿰… 2026/7/16 12:08:13