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
}
}
来源:oschina
链接:https://my.oschina.net/u/3226414/blog/3160426