内容简介:LengthFieldBasedFrameDecoder可以通过消息中的一个表示消息长度的字段值动态分隔收到的ByteBuf。在一些带有消息头的自定义协议中很有用。LengthFieldBasedFrameDecoder中有一些参数可以灵活适配大部分协议结构。
LengthFieldBasedFrameDecoder
可以通过消息中的一个表示消息长度的字段值动态分隔收到的ByteBuf。在一些带有消息头的自定义协议中很有用。
LengthFieldBasedFrameDecoder中有一些参数可以灵活适配大部分协议结构。
假设我们想设计一种协议,协议头只有一个4byte的值表示后面消息的长度,例如’HELLO’用这种消息表示为0x0005 HELLO。
我们解析是需要先读出4byte,再按照这个int值的大小读对应长度的消息。其中还有很多细节需要处理,稍有疏忽可能出现潜在问题。
而通过LengthFieldBasedFrameDecoder可以很轻松的实现。
LengthFieldBasedFrameDecoder有几个常用的配置参数。
- maxFrameLength frame最大的长度,防止太大导致内存溢出
- lengthFieldOffset 表示消息体长度的字段的offset,也就是ByteBuf的什么位置开始就是length字段了
- lengthFieldLength length字段的长度
- lengthAdjustment 有些情况可能会把header也包含到length长度中,或者length字段后面还有一些不包括在length长度内的,可以通过lengthAdjustment调节
- initialBytesToStrip 起始截掉的部分,如果传递给后面的Handler的数据不需要消息头了,可以通过这个设置
对于发送HELLO这个数据,分几种配置进行说明。HELLO表示HELLO对应的utf8字节
-
lengthFieldOffset=0
lengthFieldLength=
lengthAdjustment=0
initialBytesToStrip=0
这个解码后得到的还是0x0005HELLO的ByteBuf, 交给后面的Handler,不会出现这个ByteBuf中有下一个消息的数据或只有一部分的情况。
2.
lengthFieldOffset=0
lengthFieldLength=2
lengthAdjustment=0
initialBytesToStrip=2
这个解码后得到HELLO,因为initialBytesToStrip把length字段去掉了。
3.
lengthFieldOffset=0
lengthFieldLength=2
lengthAdjustment=-2
initialBytesToStrip=0
这种配置把length字段也算在length长度里了,所以HELLO对应的编码是
0x0007HELLO,解码后是0x0007HELLO的ByteBuf帧。
如果要去掉length字段,可以设置initialBytesToStrip
4.
lengthFieldOffset=8
lengthFieldLength=2
lengthAdjustment=4
initialBytesToStrip=0
这种情况表示length字段前面还有其他信息,例如一个固定的MagicNumber。
0xCAFEBABY 0x0005 HELLO要用lengthAdjustment找到length字段位置。
还有更多可能的组合方式可以根据自己的需求设置。
代码实现
LengthFieldBasedFrameDecoder核心逻辑在decode方法中
去掉很多异常、边界条件检查后,逻辑就比较清晰了
- 首先构造器中会计算出lengthFieldEndOffset=lengthFieldOffset + lengthFieldLength,表示length字段结束的位置。
- 判断如果当前数据可读长度不够读完length字段,就返回,等下次messageRead事件(这里没有修改ByteBuf的index)
- 计算出length字段在ByteBuf中的绝对位置,然后计算出length值
- 在通过lengthAdjustment调整下length得到最终要读的frame的长度
- 如果当前不够读的,返回,等下次messageRead事件(这里没有修改ByteBuf的index)
-
跳过initialBytesToStrip, 读出frame,并且修改ByteBuf的readIndex,返回
关于ByteBuf相关的,在后续文章中会介绍,目前可以理解为类似 Java 中的ByteBuffer,不过会有readerIndex和writerIndex。protected Object decode(ChannelHandlerContext ctx, ByteBufin) throws Exception{ if (in.readableBytes() < lengthFieldEndOffset) { return null; } int actualLengthFieldOffset = in.readerIndex() + lengthFieldOffset; long frameLength = getUnadjustedFrameLength(in, actualLengthFieldOffset, lengthFieldLength, byteOrder); frameLength += lengthAdjustment + lengthFieldEndOffset; // never overflows because it's less than maxFrameLength int frameLengthInt = (int) frameLength; if (in.readableBytes() < frameLengthInt) { return null; } in.skipBytes(initialBytesToStrip); // extract frame int readerIndex = in.readerIndex(); int actualFrameLength = frameLengthInt - initialBytesToStrip; ByteBuf frame = extractFrame(ctx, in, readerIndex, actualFrameLength); in.readerIndex(readerIndex + actualFrameLength); return frame; }
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 以太坊源码分析(36)ethdb源码分析
- [源码分析] kubelet源码分析(一)之 NewKubeletCommand
- libmodbus源码分析(3)从机(服务端)功能源码分析
- [源码分析] nfs-client-provisioner源码分析
- [源码分析] kubelet源码分析(三)之 Pod的创建
- Spring事务源码分析专题(一)JdbcTemplate使用及源码分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Django 1.0 Template Development
Scott Newman / Packt / 2008 / 24.99
Django is a high-level Python web application framework designed to support the rapid development of dynamic websites, web applications, and web services. Getting the most out of its template system a......一起来看看 《Django 1.0 Template Development》 这本书的介绍吧!