netty 数据分包、组包、粘包处理机制(一)

来源:互联网 发布:存活的数据叫删失数据 编辑:程序博客网 时间:2024/06/05 00:54


1.            frame包整体功能描述

此包主要作用于对TCP/IP数据包的分包和包重组,常用于数据的流传输,是扩展的解码器。

包目录结构如下:

netty 数据分包、组包、粘包处理机制(一) - 断鸿零雁 - 断鸿零雁的博客
 

 

2.            包中各类功能详解

(1)  FrameDecoder

抽象类,将ChannelBuffers中的二进制数据转换成有意义的数据帧(frame)对象,一般不直接调用,提供给此包中的FixedLengthFrameDecoder类、DelimiterBasedFrameDecoder类和LengthFieldBasedFrameDecoder类使用,也可以提供给其他类使用(暂不探讨);

 

在数据传输中,我们发送的数据包如下所示

 

+-----+-----+-----+

 | ABC | DEF | GHI |

 +-----+-----+-----+

 

而实际接收的包的格式为:

 

+----+-------+---+---+
 | AB | CDEFG | H | I |
 +----+-------+---+---+

 

 

产生的原因为:数据在传输过程中,产生数据包碎片(TCP/IP数据传输时大数据包无法一次传输,被拆分成小数据包,小数据包即为数据包碎片),这就造成了实际接收的数据包和发送的数据包不一致的情况。

 

而通过FrameDecoder即可实现对上述接收到的数据包的整理,重新还原成如下格式:

 

+-----+-----+-----+
 | ABC | DEF | GHI |
 +-----+-----+-----+

 

如下是一个自定义的Decoder

 

public class MyFrameDecoder extends FrameDecoder {

 

         @Override

   protected Object decode(ChannelHandlerContext ctx,

                           channel,

                           ChannelBuffer buf) throws Exception {

 

     // Make sure if the length field was received.

     if (buf.readableBytes() < 4) {

        // The length field was not received yet - return null.

        // This method will be invoked again when more packets are

        // received and appended to the buffer.

        return null;

     }

 

     // The length field is in the buffer.

 

     // Mark the current buffer position before reading the length field

     // because the whole frame might not be in the buffer yet.

     // We will reset the buffer position to the marked position if

     // there's not enough bytes in the buffer.

     buf.markReaderIndex();
 

     // Read the length field.

     int length = buf.readInt();
 

     // Make sure if there's enough bytes in the buffer.

     if (buf.readableBytes() < length) {

        // The whole bytes were not received yet - return null.

        // This method will be invoked again when more packets are

        // received and appended to the buffer.

        // Reset to the marked position to read the length field again

        // next time.

        buf.resetReaderIndex();
 
        return null;

     }

 

     // There's enough bytes in the buffer. Read it.

     ChannelBuffer frame = buf.readBytes(length);
 

     // Successfully decoded a frame.  Return the decoded frame.

     return frame;

   }

 }

 

此时,我们无需关注数据包是如何重组的,只需要做简单的验证(按照一个包验证)就可以了,FrameDecoder内部实现了组包的机制,不过,此时,需在数据的最前面封装整个数据的长度,示例中数据长度占了四个字节,即前四个字节是数据长度,后面的才是真实的数据。

(2)  FixedLengthFrameDecoder

FixedLengthFrameDecoder主要是将诸如

+----+-------+---+---+
 | AB | CDEFG | H | I |
 +----+-------+---+---+

 

此类的数据包按照指定的frame长度重新组包,比如确定长度为3,则组包为

 

+-----+-----+-----+
 | ABC | DEF | GHI |
 +-----+-----+-----+

 

构造方法为:new FixedLengthFrameDecoder(int frameLength);

 

frameLength即修正后的帧长度

 

另一个构造方法为new FixedLengthFrameDecoder(int frameLength, boolean allocateFullBuffer);

 

allocateFullBuffer如果为真,则表示初始化的ChannelBuffer大小为frameLength

 

 

(3)  Delimiters

分隔符类,DelimiterBasedFrameDecoder类的辅助类。

 

Flash XMLsocket通信采用nulDelimiter()方法,对于一般的文本采用lineDelimiter()方法

 

(4)  DelimiterBasedFrameDecoder

对接收到的ChannelBuffers按照指定的分隔符Delimiter分隔,分隔符可以是一个或者多个

 

如将以下数据包按照“\n”分隔:

 
+--------------+
 | ABC\nDEF\r\n |
 +--------------+

 

即为:

 

+-----+-----+
 | ABC | DEF |
 +-----+-----+
 

而如果按照“\r\n”分隔,则为:

 

+----------+
 | ABC\nDEF |
 +----------+

 

对于DelimiterBasedFrameDecoder中的构造方法,其中一些参数说明:

 

maxFrameLength:解码的帧的最大长度

stripDelimiter:解码时是否去掉分隔符

failFast:为true,当frame长度超过maxFrameLength时立即报TooLongFrameException异常,为false,读取完整个帧再报异常

delimiter:分隔符


0 0