netty内置解码器,netty自定义长度解码
00-1010 LineBasedFrameCodeDelimiter BasedFrameCoderfixedlengthframecoderlengthfield BasedFrameCoder摘要简介
目录
netty中的数据通过ByteBuf传输。一个ByteBuf可能包含很多有意义的数据,可以称之为帧,也就是说一个ByteBuf可以包含很多帧。
对于消息的接收方来说,接收到ByteBuf后,需要从ByteBuf中解析出有用的数据,所以需要对ByteBuf中的帧进行拆分和解析。
一般来说,不同的框架之间有一些特定的分隔符。我们可以通过这些分隔符来区分帧,从而实现对数据的分析。
Netty为我们提供了一些合适的帧解码器,可以有效的简化我们的工作。下图是netty中几种常见的帧解码器:
接下来,我们来详细介绍一下以上帧解码器的使用方法。
简介
LineBasedFrameDecoder,从名字来看,是逐行区分帧的。根据操作系统的不同,有两种换行符,即“n”和“rn”。
BasedFrameCoder的基本原理是从ByteBuf中读取相应的字符,将 n 与 rn 进行匹配,这样就可以准确地比较字符。这些帧解码器对字符的编码也有一定的要求,一般来说需要UTF-8编码。因为“n”和“r”在这样的编码中是作为一个字节出现的,在其他组合编码中不会用到,所以用“n”和“r”来判断是非常安全的。
LineBasedFrameDecoder有几个重要的属性,一个是maxLength的属性,用来检测接收到的消息长度。如果超过长度限制,将引发TooLongFrameException异常。
还有一个stripDelimiter属性,用于确定是否需要过滤掉分隔符。
还有failFast。如果该值为true,则只要帧的长度超过maxFrameLength,就会引发TooLongFrameException,而不管该帧是否被完全读取。如果该值为false,则在完整读取整个帧后将引发TooLongFrameException。
BasedFrameCoder的核心逻辑是先找到行分隔符的位置,然后根据这个位置读取相应的帧信息。下面是查找行分隔符的findEndOfLine方法:
private int findEndOfLine(final byte buff buffer){ int total length=buffer . readable bytes();int I=buffer . foreach byte(buffer . reader index()offset,totalLength - offset,ByteProcessor。FIND _ LF);if(I=0){ offset=0;if(I 0 buffer . get byte(I-1)== r ){ I-;} } else { offset=totalLength} return I;}这里使用ByteBuf的forEachByte来遍历ByteBuf。我们要找的字符是:ByteProcessor。FIND_LF。
最后,LineBasedFrameDecoder解码的对象还是一个ByteBuf。
00-1010上面提到的LineBasedFrameCoder只对行分隔符有效。如果我们的帧是用其他分隔符分割的,LineBasedFrameCoder就不会用了,所以netty提供了一个更通用的DelimiterBasedFrameDecoder,可以自定义delimiter:
公共类定界BasedFrameD
ecoder extends ByteToMessageDecoder { public DelimiterBasedFrameDecoder(int maxFrameLength, ByteBuf delimiter) { this(maxFrameLength, true, delimiter); }传入的delimiter是一个ByteBuf,所以delimiter可能不止一个字符。
为了解决这个问题在DelimiterBasedFrameDecoder中定义了一个ByteBuf的数组:
private final ByteBuf[] delimiters; delimiters= delimiter.readableBytes();
这个delimiters是通过调用delimiter的readableBytes得到的。
DelimiterBasedFrameDecoder的逻辑和LineBasedFrameDecoder差不多,都是通过对比bufer中的字符来对bufer中的数据进行截取,但是DelimiterBasedFrameDecoder可以接受多个delimiters,所以它的用处会根据广泛。
FixedLengthFrameDecoder
除了进行ByteBuf中字符比较来进行frame拆分之外,还有一些其他常见的frame拆分的方法,比如根据特定的长度来区分,netty提供了一种这样的decoder叫做FixedLengthFrameDecoder。
public class FixedLengthFrameDecoder extends ByteToMessageDecoder
FixedLengthFrameDecoder也是继承自ByteToMessageDecoder,它的定义很简单,可以传入一个frame的长度:
public FixedLengthFrameDecoder(int frameLength) { checkPositive(frameLength, "frameLength"); this.frameLength = frameLength; }
然后调用ByteBuf的readRetainedSlice方法来读取固定长度的数据:
in.readRetainedSlice(frameLength)
最后将读取到的数据返回。
LengthFieldBasedFrameDecoder
还有一些frame中包含了特定的长度字段,这个长度字段表示ByteBuf中有多少可读的数据,这样的frame叫做LengthFieldBasedFrame。
netty中也提供了一个对应的处理decoder:
public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder
读取的逻辑很简单,首先读取长度,然后再根据长度再读取数据。为了实现这个逻辑,LengthFieldBasedFrameDecoder提供了4个字段,分别是 lengthFieldOffset,lengthFieldLength,lengthAdjustment和initialBytesToStrip。
lengthFieldOffset指定了长度字段的开始位置,lengthFieldLength定义的是长度字段的长度,lengthAdjustment是对lengthFieldLength进行调整,initialBytesToStrip表示是否需要去掉长度字段。
听起来好像不太好理解,我们举几个例子,首先是最简单的:
BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes) +--------+----------------+ +--------+----------------+ Length Actual Content -----> Length Actual Content 0x000C "HELLO, WORLD" 0x000C "HELLO, WORLD" +--------+----------------+ +--------+----------------+
要编码的消息有个长度字段,长度字段后面就是真实的数据,0x000C是一个十六进制,表示的数据是12,也就是"HELLO, WORLD" 中字符串的长度。
这里4个属性的值是:
lengthFieldOffset = 0 lengthFieldLength = 2 lengthAdjustment = 0 initialBytesToStrip = 0
表示的是长度字段从0开始,并且长度字段占有两个字节,长度不需要调整,也不需要对字段进行调整。
再来看一个比较复杂的例子,在这个例子中4个属性值如下:
lengthFieldOffset = 1 lengthFieldLength = 2 lengthAdjustment = 1 initialBytesToStrip = 3
对应的编码数据如下所示:
BEFORE DECODE (16 bytes) AFTER DECODE (13 bytes) +------+--------+------+----------------+ +------+----------------+ HDR1 Length HDR2 Actual Content -----> HDR2 Actual Content 0xCA 0x000C 0xFE "HELLO, WORLD" 0xFE "HELLO, WORLD" +------+--------+------+----------------+ +------+----------------+
上面的例子中长度字段是从第1个字节开始的(第0个字节是HDR1),长度字段占有2个字节,长度再调整一个字节,最终数据的开始位置就是1+2+1=4,然后再截取前3个字节的数据,得到了最后的结果。
总结
netty提供的这几个基于字符集的frame decoder基本上能够满足我们日常的工作需求了。当然,如果你传输的是一些更加复杂的对象,那么可以考虑自定义编码和解码器。自定义的逻辑步骤和上面我们讲解的保持一致就行了。
到此这篇关于netty中的frame解码器的文章就介绍到这了,更多相关netty解码器内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。