我们说一下编码和解码,或者数据从一种特定协议的格式到另一个格式的转换,交给编解码器的组件来处理,Netty提供了多种组件,简化了支持广泛的协议而创建自定义的编解码器的过程
我们定义如何解析在两个节点之间来回传输的原始字节,以及如何将其和目标应用程序的数据格式进行互相转换,这种转换逻辑由编解码器处理,编解码器由编码器和解码器组成
什么是编解码器
编码器可以将消息转换为适合于传输的格式,例如字节流,解码器则是将网络字节流转换回应用程序的消息格式
我们将会说两种常见的编解码器类
分别是将字节解码为消息 — ByteToMessageDecoder 和 ReplayingDecoder
将一种消息类型解码为另一种 — MessageToMessageDecoder
在我们需要为ChannelPipeline的下一个ChannelInboundHandler转换入站的数据时候可讷讷个用到
基础抽象类ByteToMessageDecoder
字节解码为消息是一种常见的任务,Netty提供了基类ByteToMessageDecoder,这个类会对入站的数据进行缓冲,直到准备好处理
我们接受了一个包含了int的字节流,每个int需要单独的处理,这时候,解析这个字节流,就需要扩展ByteToMessageDecoder类
我们每次从ByteBuf中读取4个字节,然后解码为一个int,然后加到List中,当没有更多的元素可以加入的时候,进行放行
代码如下:
我们只需要校验一下剩余数据是否足够满足一个int,就可以进行解码了
然后是抽象类 ReplayingDecoder
扩展了ByteToMessageDecoder,自定义了一个ByteBuf实现
ReplayingDecoderByteByf,
<S>指定了decode返回的类型
扩展的解码器代码如下
从byte提取的int会被加到List中,如果没有足够的字节可以用,readInt将会抛出一个异常,等待有足够的数据可以供读取的时候,decode会被再次调用
但是实际上ReplayingDecoder会稍慢于ByteToMessageDecoder
所以还是经常使用ByteToMessageDecoder
然后是MessageToMessageDecoder
下面的抽象基类在两个消息格式之间进行转换
类型I指定了decode()方法的输入参数msg的类型,这是必须要实现的方法
对应的decode 方法的API如下
我们编写一个从Integer转换为String的解码器来扩展MessageToMessageDecoder<Integer>,其decode会将Integer转换为String
解码的流程如下
然后是TooLongFrameException类
Netty是一个异步框架,所以需要在字节可以再解码之前进行缓存,为了避免缓存过多的数据耗尽可用的内存,提供了该异常,避免解码器在超过指定的大小限制的时候抛出
如何处理这个异常完全取决于用户,某些协议可能返回特殊的响应
我们看一下如何抛出这个异常
编码器
解码器对应的就是编码器,编码器实现了ChannelOutboundHandler
我们尝试编写一些编码器
将消息编码为字节
将消息编码为消息
基础的抽象基类MessageToByteEncoder
一种逆向的操作
将消息进行编码为字节
<I>的泛型是创建MessageToByteEncoder的时候的声明的
这个类相比解码器少了一个方法,因为在Channel关闭后产生消息并没有什么意义
我们下面展示的ShortToByteEncoder,其接受一个Short类型的实例为消息,编码为原子类型值,并进行写入ByteBuf中,随后交给下一个 ChannelOutboundHandler
代码如下
抽象类MessageToMessageEncoder
用于不同类型的消息的转换
对于这个抽象类,我们只需要实现一个encode()方法
我们实现了一个IntegerToStringEncoder 扩展了 MessageToMessageEncoder
抽象的编解码器类 ByteToMessageCodec
我们要将字节解码为某种消息,然后再次进行编码,ByteToMessageCodec可以处理这个,结合了ByteToMessageDecoder和逆向 MessageToByteEncoder
常见的ByteToMessageCodec API如下
然后是MessageToMessageCodec
我们看到了Encoder以一种消息格式变为了另一种的消息的格式
我们可以利用MessageToMessageCodec,帮助其在单个类中实现转换的往返过程
主要的API方法有:
方便我们在不同的消息API中来回转换数据
代码如下