LengthFieldBasedFrameDecoder使用示例
2017-06-15 18:33
585 查看
转载自:http://blog.csdn.net/z69183787/article/details/52980699
http://blog.163.com/linfenliang@126/blog/static/127857195201210821145721/
LengthFieldBasedFrameDecoder是Netty中一个很重要的解码器,因为相比于其他的普通的解码器,这个解码器用的场景更多。
定义一个这样的协议类:
LengthFieldBasedFrameDecoder的构造方法中有几个重要的参数:
如下设置时:
例如对于数据:
现在自定义一个decoder,这个类继承LengthFieldBasedFrameDecoder,来解析刚才定义的CustomMsg:
自定义一个encoder来编码CustomMsg,代码如下:
http://blog.163.com/linfenliang@126/blog/static/127857195201210821145721/
LengthFieldBasedFrameDecoder是Netty中一个很重要的解码器,因为相比于其他的普通的解码器,这个解码器用的场景更多。
定义一个这样的协议类:
public class CustomMsg { //类型 系统编号 0xAB 表示A系统,0xBC 表示B系统 private byte type; //信息标志 0xAB 表示心跳包 0xBC 表示超时包 0xCD 业务信息包 private byte flag; //主题信息的长度 private int length; //主题信息 private String body; …… }规定两个系统通过Netty去发送这样的一个格式的信息,CustomMsg中包含这样的几类信息:type表示发送端的系统类型;flag表示发送信息的类型,是业务数据,还是心跳包数据;length表示主题body的长度;body表示主题信息。
LengthFieldBasedFrameDecoder的构造方法中有几个重要的参数:
maxFrameLength:解码时,处理每个帧数据的最大长度 lengthFieldOffset :存放帧数据的长度数据的起始位(偏移位) lengthFieldLength:长度属性的长度,即存放整个大数据包长度的字节所占的长度 lengthAdjustmen:长度调节值,在总长被定义为包含包头长度时,修正信息长度。 initialBytesToStrip:跳过的字节数,根据需要跳过lengthFieldLength个字节,以便接收端直接接受到不含“长度属性”的内容 failFast :为true,当frame长度超过maxFrameLength时立即报TooLongFrameException异常,为false,读取完整个帧再报异常简单举个例子说下含义,例如对于数据:
BEFORE DECODE (14 bytes) +---------+----------------+ | Length | Actual Content| | 0x000C | "HELLO, WORLD"| +---------+----------------+0x000C表示有效数据是12个字节,如下设置时:
lengthFieldOffset = 0 lengthFieldLength = 2 lengthAdjustment = 0 initialBytesToStrip = 0解析完数据为:
| 0x000C | "HELLO, WORLD" |此时数据格式不做任何改变(没有跳过任何字节)。
如下设置时:
lengthFieldOffset = 0 lengthFieldLength = 2 lengthAdjustment = 0 initialBytesToStrip = 2解析完数据为:
| "HELLO, WORLD" |但由于前两个(lengthFieldOffset = 0,lengthFieldLength = 2)字节是表示帧长度的字节,不计入数据,故真实的数据是除去了长度数据后剩下的12个字节。
例如对于数据:
BEFORE DECODE (14 bytes) +---------+----------------+ | Length | Actual Content| | 0x000E | "HELLO, WORLD"| +---------+----------------+此处定义的Length为0x000E,占了两个字节,表示的整个帧长度为14(2 + 12)个字节。如下设置时:
lengthFieldOffset = 0 lengthFieldLength = 2 lengthAdjustment = -2 initialBytesToStrip = 0解析完数据为:
| 0x000E | "HELLO, WORLD" |由于设置的lengthAdjustment = -2 (即 the length of the Length field),故修正的信息实际长度补2,即解码时往前推2个字节,解码后还是14个字节长度。更具体的还请自行百度。
现在自定义一个decoder,这个类继承LengthFieldBasedFrameDecoder,来解析刚才定义的CustomMsg:
public class CustomDecoder extends LengthFieldBasedFrameDecoder { //判断传送客户端传送过来的数据是否按照协议传输,头部信息的大小应该是 byte+byte+int = 1+1+4 = 6 private static final int HEADER_SIZE = 6; private byte type; private byte flag; private int length; private String body; public CustomDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, boolean failFast) { super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, failFast); } @Override protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { if (in == null) { return null; } if (in.readableBytes() < HEADER_SIZE) { throw new Exception("可读信息段比头部信息都小,你在逗我?"); } //注意在读的过程中,readIndex的指针也在移动 type = in.readByte(); flag = in.readByte(); length = in.readInt(); if (in.readableBytes() < length) { throw new Exception("body字段你告诉我长度是"+length+",但是真实情况是没有这么多,你又逗我?"); } ByteBuf buf = in.readBytes(length); byte[] req = new byte[buf.readableBytes()]; buf.readBytes(req); body = new String(req, "UTF-8"); CustomMsg customMsg = new CustomMsg(type,flag,length,body); return customMsg; } }头部信息的大小是6,因为byte是一个字节,int是四个字节,那么头部大小就是6个字节,构造函数的入参数据是:
maxFrameLength = 1024 * 1024 lengthFieldOffset = 2 lengthFieldLength = 4 lengthAdjustment = 0 initialBytesToStrip = 0lengthFieldLength指的就是CustomMsg中length这个属性的大小,是int型,所以是4;lengthFieldOffset指的就是length字段的起始位置,因为前面有type和flag两个属性,且这两个属性都是byte,两个就是2字节,所以偏移量是2;lengthAdjustment指的是length这个属性的值,假如body长度是40,有时候,有些人喜欢将length写成44,因为length本身还占有4个字节,这样就需要调整一下,那么就需要-4,我们这边没有这样做,所以写0就可以了。
自定义一个encoder来编码CustomMsg,代码如下:
public class CustomEncoder extends MessageToByteEncoder<CustomMsg> { @Override protected void encode(ChannelHandlerContext ctx, CustomMsg msg, ByteBuf out) throws Exception { if(null == msg){ throw new Exception("msg is null"); } String body = msg.getBody(); byte[] bodyBytes = body.getBytes(Charset.forName("utf-8")); out.writeByte(msg.getType()); out.writeByte(msg.getFlag()); out.writeInt(bodyBytes.length); out.writeBytes(bodyBytes); } }
相关文章推荐
- 过长内容分成了多次发送 问题 LengthFieldBasedFrameDecoder使用
- Netty的LengthFieldBasedFrameDecoder使用
- netty LengthFieldBasedFrameDecoder 使用实例
- netty 过长内容分成了多次发送 问题 LengthFieldBasedFrameDecoder使用
- Netty LengthFieldBasedFrameDecoder使用场景分析
- netty源码分析之FrameDecoder(LengthFieldBasedFrameDecoder)
- Netty学习(六)-LengthFieldBasedFrameDecoder解码器
- LengthFieldBasedFrameDecoder和LengthFieldPrepender
- Netty LengthFieldBasedFrameDecoder
- 一起学Netty(九)之LengthFieldBasedFrameDecoder
- 自顶向下深入分析Netty(八)-- LengthFieldBasedFrameDecoder
- LengthFieldBasedFrameDecoder
- Netty LengthFieldBasedFrameDecoder
- LengthFieldPrepender和LengthFieldBasedFrameDecoder
- Netty权威指南 第2版学习笔记7——MessagePack编解码及LengthFieldBasedFrameDecoder
- 一起学Netty(九)之LengthFieldBasedFrameDecoder
- netty——LengthFieldBasedFrameDecoder实例(解决半包)
- 一起学Netty(九)之LengthFieldBasedFrameDecoder
- Netty学习(四)—LengthFieldBasedFrameDecoder解码器
- [netty]--最通用TCP黏包解决方案:LengthFieldBasedFrameDecoder和LengthFieldPrepender