Netty之编解码器框架

什么是编解码器

每个网络应用程序都必须定义如何解析在两个节点之间来回传输的原始字节,以及如何将其和目标应用程序的数据格式做相互转换。这种转换逻辑由编解码器处理,编解码器由编码器(Encoder)和解码器(Decoder)组成,它们每种都可以将字节流从一种格式转换为另一种格式。

我们常用的编解码器是:

  • MessageToByteEncoder:将数据从本身的格式转换为字节流。出站的时候用。
  • ByteToMessageDecoder:将字节流转换为它原来的格式。入站的的时候用。

解码器

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

因为解码器是负责将入站数据从一种格式转换到另一种格式的,所以Netty 的解码器实现了ChannelInboundHandler。
什么时候会用到解码器呢?很简单:每当需要为ChannelPipeline 中的下一个ChannelInboundHandler 转换入站数据时会用到。此外,得益于ChannelPipeline 的设计,可以将多个解码器链接在一起,以实现任意复杂的转换逻辑。

ByteToMessageDecoder

在这里插入图片描述

将字节解码为消息(或者另一个字节序列)是一项如此常见的任务,以至于Netty 为它提供了一个抽象的基类:ByteToMessageDecoder。由于你不可能知道远程节点是否会一次性地发送一个完整的消息,所以这个类会对入站数据进行缓冲,直到它准备好处理。

在这里插入图片描述
示例:
将字节流(存储在ByteBuf中)解码为 int 流(这里是自动装箱为Integer存储在List中)。
在这里插入图片描述
在这里插入图片描述
注意:
一旦消息被编码或解码,它就会被ReferenceCountUtil.release(message) 调用自动释放。如果想要保留引用稍后使用,可以调用ReferenceCountUtil.retain(message)

ReplayingDecoder

在这里插入图片描述
看了前面的ByteToMessageDecoder示例代码,我们会觉得每次判断in.readableBytes()十分不优雅。ReplayingDecoder可以让我们不必调用readableBytes()方法。它有一个自定义的ByteBuf实现——ReplayingDecoderBytebuf,其将在内部执行readableBytes()。

示例:
在这里插入图片描述

  • 如果没有足够的字节可处理了,readInt() 方法的实现将抛出一个异常(实际上是一个 Signal),其将在基类中被捕获并处理。
  • 如果有更多的字节可处理,decode() 会被再次调用。

注意:

  • 并不是所有的ByteBuf操作都被支持。
  • ReplayingDecoder稍慢于ByteToMessageDecoder。

总而言之:如果使用 ByteToMessageDecoder 觉得不会很复杂,就使用 ByteToMessageDecoder 。否则,使用ReplayingDecoder。

MessageToMessageDecoder

在这里插入图片描述
在这里插入图片描述
示例:
将 Integer 转换为 String 。
在这里插入图片描述
在这里插入图片描述

TooLongFrameException

由于Netty 是一个异步框架,所以需要在字节可以解码之前在内存中缓冲它们。因此,不能让解码器缓冲大量的数据以至于耗尽可用的内存。为了解除这个常见的顾虑,Netty 提供了TooLongFrameException 类,其将由解码器在帧超出指定的大小限制时抛出。
为了避免这种情况,你可以设置一个最大字节数的阈值,如果超出该阈值,则会导致抛出一个TooLongFrameException(随后会被ChannelHandler.exceptionCaught()方法捕获)。然后,如何处理该异常则完全取决于该解码器的用户。某些协议(如HTTP)可能允许你返回一个特殊的响应。而在其他的情况下,唯一的选择可能就是关闭对应的连接。

示例:
在这里插入图片描述

编码器

  • 将消息编码为字节——MessageToByteEncoder
  • 将消息编码为消息——MessageToMessageEncoder

MessageToByteEncoder

在这里插入图片描述
在这里插入图片描述
示例:
在这里插入图片描述
在这里插入图片描述

MessageToMessageEncoder

在这里插入图片描述
在这里插入图片描述
示例:
在这里插入图片描述
在这里插入图片描述

抽象的编解码器类

我们一直将解码器和编码器作为单独的实体讨论,但是你有时将会发现在同一个类中管理入站和出站数据和消息的转换是很有用的。Netty 的抽象编解码器类正好用于这个目的,因为它们每个都将捆绑一个解码器/编码器对,以处理我们一直在学习的这两种类型的操作。这些类同时实现了ChannelInboundHandler 和ChannelOutboundHandler 接口。
为什么我们并没有一直优先于单独的解码器和编码器使用这些复合类呢?因为通过尽可能地将这两种功能分开,最大化了代码的可重用性和可扩展性,这是Netty 设计的一个基本原则。

ByteToMessageCodec

在这里插入图片描述
在这里插入图片描述
结合了 ByteToMessageDecoder 和 MessageToByteEncoder 。
在这里插入图片描述

MessageToMessageCodec

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

CombinedChannelDuplexHandler

在这里插入图片描述
不像 ByteToMessageCodec 和 MessageToMessageCodec 继承的 ChannelDuplexHandler 那样,继承 ChannelInboundHandlerAdapter 又实现 ChannelOutboundHandler,而是充当 ChannelInboundHandler 和 ChannelOutboundHandler 的容器。这样既避免了结合一个解码器和编码器对可重用性造成的影响,又能拥有将解码器和编码器作为一个单独的单元来部署的便利性。
示例:
解码器:在这里插入图片描述
编码器:
在这里插入图片描述
编解码器:
在这里插入图片描述
个人认为这个类除了能让你的 ChannelInitializer 更加简洁,确实没什么用。

参考自:《Netty实战》

©️2020 CSDN 皮肤主题: 岁月 设计师: pinMode 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值