Netty源码面试解析(八) - 解码上

简介: 就像很多标准的架构模式都被各种专用框架所支持一样,常见的数据处理模式往往也是目标实现的很好的候选对象,它可以节省开发人员大量的时间和精力。当然这也适应于本文的主题:编码和解码,或者数据从一种特定协议的格式到另一种格式的转 换。这些任务将由通常称为编解码器的组件来处理Netty 提供了多种组件,简化了为了支持广泛 的协议而创建自定义的编解码器的过程例如,如果你正在构建一个基于 Netty 的邮件服务器,那 么你将会发现 Netty 对于编解码器的支持对于实现 POP3、IMAP 和 SMTP 协议来说是多么的宝贵

0 什么是编解码器

每个网络应用程序都必须定义


  • 如何解析在两个节点之间来回传输的原始字节
  • 如何将其和目标应用程序的数据格式做相互转换


这种转换逻辑由编解码器处理,编解码器由编码器和解码器组成,它们每种都可以将字节流从一种格式转换为另一种格式


那么它们的区别是什么呢?

如果将消息看作是对于特定的应用程序具有具体含义的结构化的字节序列— 它的数据。那 么编码器是将消息转换为适合于传输的格式(最有可能的就是字节流);而对应的解码器则是将 网络字节流转换回应用程序的消息格式。因此,编码器操作出站数据,而解码器处理入站数据。

记住这些背景信息,接下来让我们研究一下 Netty 所提供的用于实现这两种组件的类。

1 Netty解码概述

1.png

1.1 本文目标

  • 解码器抽象的解码过程
  • Netty里面有哪些拆箱即用的解码器

Netty 的解码器类:

  • 将字节解码为消息
    ByteToMessageDecoder 和 ReplayingDecoder
  • 将一种消息类型解码为另一种
    MessageToMessageDecoder

解码器负责将入站数据从一种格式转到另一种,所以 Netty 解码器实

现了 ChannelInboundHandler 也很自然。

  • 什么时候会用解码器?
    每当需为 ChannelPipeline 中的下一个 ChannelInboundHandler 转换入站数据时。

得益于ChannelPipeline 的设计,可以将多个解码器连接在一起,以实现任意复杂的转换逻辑,这也是 Netty 是如何支持代码的模块化以及复用的一个很好的例子。

案例代码

1.png

1.png

1.png

2 抽象解码器 ByteToMessageDecoder

2.1 示例

Netty 提供抽象基类:ByteToMessageDecoder,将字节解码为消息(或另一个字节序列)。

由于你不可能知道远程节点是否会一次性发送一个完整消息,所以该类会缓冲入站数据,直到它准备好处理。


ByteToMessageDecoderAPI

1.png

假设你接收了一个包含简单 int 的字节流,每个 int 都需要被单独处理

在这种情况下,你需要从入站ByteBuf中读取每个 int,并将它传递给ChannelPipeline 中的下一个 ChannelInboundHandler

为了解码这个字节流,你要扩展 ByteToMessageDecoder类(原子类型的 int 在被添加到 List 中时,会被自动装箱为 Integer)


1.png

每次从入站 ByteBuf 中读取 4 字节,将其解码为一个 int,然后将它添加到一个 List 中

当没有更多的元素可以被添加到该 List 中时,它的内容将会被发送给下一个 Channel- InboundHandler

ToIntegerDecoder类扩展了ByteToMessageDecoder

1.png

虽然ByteToMessageDecoder可以很简单地实现这种模式,但是你可能会发现,在调用 readInt()前不得不验证所输入的 ByteBuf 是否具有足够的数据有点繁琐

在下一节中, 我们将讨论 ReplayingDecoder,它是一个特殊的解码器,以少量的开销消除了这个步骤

2.2 源码解析

1.png

下面开始解析解码流程的源码:

2.2.1 累加字节流

1.png

其中的cumulator

image.png

看一下这个MERGE_CUMULATOR

public static final Cumulator MERGE_CUMULATOR = new Cumulator() {
    @Override
    public ByteBuf cumulate(ByteBufAllocator alloc, ByteBuf cumulation, ByteBuf in) {
        ByteBuf buffer;
        // 当前写指针后移一定字节,若超过最大容量,则扩容
        if (cumulation.writerIndex() > cumulation.maxCapacity() - in.readableBytes()
                || cumulation.refCnt() > 1) {
            // Expand cumulation (by replace it) when either there is not more room in the buffer
            // or if the refCnt is greater then 1 which may happen when the user use slice().retain() or
            // duplicate().retain().
            //
            // See:
            // - https://github.com/netty/netty/issues/2327
            // - https://github.com/netty/netty/issues/1764
            buffer = expandCumulation(alloc, cumulation, in.readableBytes());
        } else {
            buffer = cumulation;
        }
        // 将当前数据写到累加器
        buffer.writeBytes(in);
        // 释放读进的数据对象
        in.release();
        return buffer;
    }
};

2.2.2 调用子类 decode 方法进行解析

进入该方法查看源码

1.png

image.png

2.2.2 将解析到的 ByteBuf 向下传播

1.png

注意到上图中的如下代码段:

1.png

1.png

编解码器中的引用计数

对于编码器和解码器,一旦消息被编码或解码,它就会被 ReferenceCountUtil.release(message)调用自动释放。

若需要保留引用以便稍后使用,可调用 ReferenceCountUtil.retain(message),这会增加该引用计数,从而防止该消息被释放。


3 固定长度解码器

1.png

4 行解码器

4.1 定位行尾

1.png

1.png

4.2 非丢弃模式

1.png

1.png

找到换行符

1.png

找不到换行符

1.png

image.png

4.3 丢弃模式

1.png

找到换行符

1.png

找不到换行符

1.png

参考

  • 《Netty实战》
目录
相关文章
|
4天前
|
数据采集 机器学习/深度学习 数据挖掘
Python数据清洗与预处理面试题解析
【4月更文挑战第17天】本文介绍了Python数据清洗与预处理在面试中的常见问题,包括Pandas基础操作、异常值处理和特征工程。通过示例代码展示了数据读取、筛选、合并、分组统计、离群点检测、缺失值和重复值处理、特征缩放、编码、转换和降维。强调了易错点,如忽视数据质量检查、盲目处理数据、数据隐私保护、过度简化特征关系和忽视模型输入要求。掌握这些技能和策略将有助于在面试中脱颖而出。
23 8
|
7天前
|
调度 Python
Python多线程、多进程与协程面试题解析
【4月更文挑战第14天】Python并发编程涉及多线程、多进程和协程。面试中,对这些概念的理解和应用是评估候选人的重要标准。本文介绍了它们的基础知识、常见问题和应对策略。多线程在同一进程中并发执行,多进程通过进程间通信实现并发,协程则使用`asyncio`进行轻量级线程控制。面试常遇到的问题包括并发并行混淆、GIL影响多线程性能、进程间通信不当和协程异步IO理解不清。要掌握并发模型,需明确其适用场景,理解GIL、进程间通信和协程调度机制。
27 0
|
7天前
|
API Python
Python模块化编程:面试题深度解析
【4月更文挑战第14天】了解Python模块化编程对于构建大型项目至关重要,它涉及代码组织、复用和维护。本文深入探讨了模块、包、导入机制、命名空间和作用域等基础概念,并列举了面试中常见的模块导入混乱、不适当星号导入等问题,强调了避免循环依赖、合理使用`__init__.py`以及理解模块作用域的重要性。掌握这些知识将有助于在面试中自信应对模块化编程的相关挑战。
20 0
|
8天前
yolo-world 源码解析(六)(2)
yolo-world 源码解析(六)
18 0
|
8天前
yolo-world 源码解析(六)(1)
yolo-world 源码解析(六)
12 0
|
8天前
yolo-world 源码解析(五)(4)
yolo-world 源码解析(五)
19 0
|
8天前
yolo-world 源码解析(五)(1)
yolo-world 源码解析(五)
31 0
|
8天前
yolo-world 源码解析(二)(2)
yolo-world 源码解析(二)
21 0
|
8天前
Marker 源码解析(二)(3)
Marker 源码解析(二)
13 0

推荐镜像

更多