netty内置解码器,netty自定义长度解码

  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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: