Netty学习笔记12——编解码器框架

来源:互联网 发布:淘宝买书有什么好店铺 编辑:程序博客网 时间:2024/06/06 02:03

文本内容来自《Netty实战》学习笔记

一、解码器

1.把字节解码为消息

1) ByteToMessageDecoder

方法:

decode(ChannelHandlerContext ctx,ByteBuf in,List<Object> out)必须实现的抽象方法。调用时传入一个ByteBuf,以及一个用来添加解码消息的List。对这个方法的调用将会重复进行,直到确定没有新的元素被添加到该List,或者该ByteBuf中没有更多可读取的字节时为止。然后,如果该List不为空,那么它的内容将会被传递人ChannelPipeline中的下一个ChannelInboundHandler。decodeLast(ChannelHandlerContext ctx,ByteBuf in,List<Object> out)Netty提供的这个默认实现只是简单 调用了decode()方法。当Channel的状态变为非活动时,这个方法将会被调用一次。可以重写该方法以提供特殊的处理。

示例:每次从入站ByteBuf读取4个字节,将其解码为一个int,然后将它添加到一个List中。当没有更多的元素中以被添加到该List中时,它的内容将会发送给下一个Channel-InboundHandler。

public class ToIntegerDecoder extends ByteToMessageDecoder{    @Override    public void decode(ChannelHandlerContext ctx,ByteBuf in, List<Object> out) throws Exception{        if (in.readableBytes() >= 4){              out.add(in.readInt());        }    }}

原来类型 int被添加到List中时,会被自动装箱为Integer。

一旦消息被编码或者解码,它就会被ReferenceCountUtil.release(message)调用自动释放。如果需要保留引用以便稍后使用,那么可以调用ReferenceCountUtil.retain(message)方法,它会将增加引用计数,从而防止该消息被释放。

2)ReplayingDecoder

ReplayingDecoder扩展了ByteToMessageDecoder类,使我们不必调用readableBytes()方法。它通过使用一个自定义的ByteBuf实现ReplayingDecodeerByteBuf包装传入的ByteBuf实现了这一点,其将在内部执行该调用。
该类的完整声明:

public abstract class ReplayingDecoder<S> extends ByteToMessageDecoder

类型参数S指定了用于状态管理的类型,其中Void代表不需要状态管理。
仍然实现上述案例:

public class ToIntegerDecoder2 extends ReplayingDecoder<Void>{    @Override    public void decode (ChannelHandlerContext ctx,ByteBuf in,List<Object> out) throws Exception{           out.add(in.readInt());    }}

在读取readInt时,如果没有足够的字节可用,可抛出一个Error。其将在基类里捕获并处理。
注意点:

  1. 不是所有的ByteBuf操作都被支持。如果调用了一个不被支持的方法,将会抛出一个UnsupportedOperationException
  2. ReplayingDecoder 稍慢于ByteToMessageDecoder

其它的解码器

  • io.netty.handler.codec.LineBasedFrameDecoder 使用了行尾控制字符来解析消息数据
  • io.netty.handler.codec.http.HttpObjectDecoder HTTP数据的解码器。

2.将一种消息类型解码为另一种

MessageToMessageDecoder
用来在两个消息格式之间转换。

decode(ChannelHandlerContext ctx,I msg,List<Object> out)对于每个需要被解码为另一种格式的入站消息来说,该方法都将会被调用。解码消息随后会被传递人ChannelPipeline中的下一个ChannelInboundHandler。

下面示例是IntegerToStringDecoder的实现。

public class IntegerToStringDecoder extends MessageToDecoder<Integer>{    @Override    public void decode(ChannelHandlerContext ctx,Integer msg , List<Object> out) throws Exception{        out.add(String.valueOf(msg));    }}

3. 解码器在帧超出指定的大小限制时抛出异常

TooLongFrameException类

public class SafeByteToMessageDecoder extends ByteToMessageDecoder{    private static final int MAX_FRAME_SIZE = 1024;    @Override    public void decode(ChannelHandlerContext ctx,ByteBuf in,List<Object> out) throws Exception{        int readable = in.radableBytes();        if(readable > MAX_FRAME_SIZE){            in.skipBytes(readable);            throw new TooLongFrameException("Frame too big!");        }    }}

二、编码器

编码器实现了ChannelOutboundHandler,将出站数据从一种格式转换为另一种格式。类似的,有:
MesageToByteEncoder
MessageToMessageEncoder

CombinedChannelDuplexHandler类

其声明为:

public class CombinedChannelDuplexHandler,<I extends ChannelInboundHandler, o extends ChannelOutboundHandler>

这个类充当了ChannelInboundHandler和ChannelOutboundHandler的容器。
这个类我觉得不用也没关系,以后用到时再详细看看。

这前几篇文章介绍了几个内置编解码器。

Netty权威指南 第2版学习笔记4——TCP粘包/拆包问题的解决之道
Netty权威指南 第2版学习笔记5——分隔符和定长解码器的应用
Netty权威指南 第2版学习笔记6——常见序列化与反序列化框架
Netty权威指南 第2版学习笔记7——MessagePack编解码及LengthFieldBasedFrameDecoder

原创粉丝点击