Netty常用的几种解码器

六月ゝ 毕业季﹏ 提交于 2020-02-26 00:56:56

Netty常用的几种解码器

Decoder解码器

ByteToMessageDecoder

将byte数据转换为一个消息类

方法名称 描述
Decode 这是您需要实现的唯一抽象方法。通过具有输入字节的ByteBuf和添加了已解码消息的List进行调用。重复调用encode(),直到列表返回时为空。然后将List的内容传递到管道中的下一个处理程序。
decodeLast 所提供的默认实现只调用了decode()。当Channel变为非活动状态时,此方法被调用一次。提供特殊的替代

举个例子:

假设我们接收一个包含简单整数的字节流,每个都单独处理。在本例中,我们将从入站 ByteBuf 读取每个整数并将其传递给 pipeline 中的下一个ChannelInboundHandler。“解码”字节流成整数我们将扩展ByteToMessageDecoder,实现类为“ToIntegerDecoder”

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());  
        }
    }
}

MessageToMessageDecoder

将一种消息类转换为另一种消息类

方法名称 描述
decode 解码是您需要实现的唯一抽象方法。要求将每个入站消息解码为另一种格式。然后,已解码的消息将传递到管道中的下一个ChannelInboundHandler
decodeLast 所提供的默认实现只调用了decode()。当Channel变为非活动状态时,此方法被调用一次。提供特殊的替代

举个例子:入站消息是按照在类定义中声明的参数类型(这里是 Integer) 而不是 ByteBuf来解析的。在之前的例子,解码消息(这里是String)将被添加到List,并传递到下个 ChannelInboundHandler。

public class IntegerToStringDecoder extends
        MessageToMessageDecoder<Integer> {

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

DelimiterBasedFrameDecoder

接收ByteBuf由一个或多个分隔符拆分,如NUL或换行符.它与 LineBasedFrameDecoder 相似,只不过它可以自定义我们的消息分隔符

FixedLengthFrameDecoder

提取固定长度。构造器传入数据帧的长度,可以按照此长度截取数据

LengthFieldBasedFrameDecoder

读取头部长度并提取帧的长度。大部分时候帧的大小被编码在头部,这种情况可以使用LengthFieldBasedFrameDecoder,它会读取头部长度并提取帧的长度

解析一下它构造器中的几个参数的意义:

maxFrameLength 根据协议最大87
lengthFieldOffset 长度域偏移量,指的是长度域位于整个数据包字节数组中的下标;
lengthFieldLength - 长度域的自己的字节数长度。
lengthAdjustment – 长度域的偏移量矫正。
如果长度域的值,除了包含有效数据域的长度外,还包含了其他域(如长度域自身)长度,那么,就需要进行矫正。矫正的值为:包长 - 长度域的值 – 长度域偏移 – 长度域长。
initialBytesToStrip – 丢弃的起始字节数。丢弃处于有效数据前面的字节数量。

这个解码器比较复杂,下面举一个实际例子解释一下:

假如,有如下硬件协议:

设备类型 预留 消息类型 有效数据长度 内容 校验
1Byte 1Byte 2Byte 1Byte 2Byte nByte 1Byte 1Byte

头: 起始标志为一个字节,固定为:0x55

设备类型: 1:车载主机,2:厢内系统(奇辉)

预留: 固定填写0xff

消息类型: 表示该次通信中整帧的类型。

有效数据长度: 表示为该次通信中有效数据内容的长度。高位在前,低位在后。

内容: 有效数据,数据内容根据消息类型加以区分。

校验: 和校验。

尾: 终止标志为一个字节,固定为:0x88

那么上面协议,就可以用如下参数进行解析:

maxFrameLength 10240 根据协议,有可能发送数据量比较大,如果协议没提到,这个可以设置的大一点
lengthFieldOffset 5 在上面就是指的有效数据长度,也就是这个值 为 5,从帧的头部偏移5个字节才是有效数据长度
lengthFieldLength - 2 这里值得是长度域占两个字节
lengthAdjustment – 2 长度域的偏移量矫正。因为根据协议有效数据长度字段是指的后面的内容长度,不包含它自身,那么在进行解析的时候需要对整个长度域进行调整,调整的长度就是去掉有效数据长度所占用的2个字节
initialBytesToStrip – 0 丢弃的起始字节数。这里我们不进行字节丢弃所以传入 0

new LengthFieldBasedFrameDecoder(10240, 5, 2, 2, 0)

LineBasedFrameDecoder

接收ByteBuf以分割线结束,如"\n"和"\r\n"

public class LineBasedHandlerInitializer extends ChannelInitializer<Channel> {

    @Override
    protected void initChannel(Channel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new LineBasedFrameDecoder(65 * 1024));   //1
        pipeline.addLast(new FrameHandler());  //2
    }

    public static final class FrameHandler extends SimpleChannelInboundHandler<ByteBuf> {
        @Override
        public void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {  //3
            // Do something with the frame
        }
    }
}

Encoder编码器

MessageToByteEncoder

之前我们学习了如何使用 ByteToMessageDecoder 来将字节转换成消息,现在我们使用 MessageToByteEncoder 实现相反的效果

方法名称 描述
encode The encode method is the only abstract method you need to implement. It is called with the outbound message, which this class will encodes to a ByteBuf. The ByteBuf is then forwarded to the next ChannelOutboundHandler in the ChannelPipeline.

这个类只有一个方法,而 decoder 却是有两个,原因就是 decoder 经常需要在 Channel 关闭时产生一个“最后的消息”。出于这个原因,提供了decodeLast(),而 encoder 没有这个需求。

举个例子:

encoder 收到了 Short 消息,编码他们,并把他们写入 ByteBuf。 ByteBuf 接着前进到下一个 pipeline 的ChannelOutboundHandler。每个 Short 将占用 ByteBuf 的两个字节

public class ShortToByteEncoder extends
        MessageToByteEncoder<Short> {  
    @Override
    public void encode(ChannelHandlerContext ctx, Short msg, ByteBuf out)
            throws Exception {
        out.writeShort(msg);  
    }
}

MessageToMessageEncoder

我们已经知道了如何将入站数据从一个消息格式解码成另一个格式。现在我们需要一种方法来将出站数据从一种消息编码成另一种消息。MessageToMessageEncoder 提供此功能,见表7.4,同样的只有一个方法,因为不需要产生“最后的消息”。

方法名称 描述
encode 编码方法是您需要实现的唯一抽象方法。对于使用write(...)编写的每条消息,都会对其进行调用,以将该消息编码为一个或多个新的出站消息。然后将编码后的消息转发

我们将要解码 Integer 消息到 String 消息。可简单使用 MessageToMessageEncoder

举个例子:

encoder 从出站字节流提取 Integer,以 String 形式传递给ChannelPipeline 中的下一个 ChannelOutboundHandler 。

public class IntegerToStringEncoder extends
        MessageToMessageEncoder<Integer> { //1

    @Override
    public void encode(ChannelHandlerContext ctx, Integer msg, List<Object> out)
            throws Exception {
        out.add(String.valueOf(msg));  //2
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!