您的位置:首页 > 编程语言 > Java开发

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

2018-02-08 00:00 411 查看
摘要: netty 数据分包、组包、粘包处理机制(一)

1. frame包整体功能描述

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

包目录结构如下:



2.包中各类功能详解

(1) FrameDecoder

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

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



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



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

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



如下是一个自定义的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主要是将诸如



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



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

frameLength即修正后的帧长度

另一个构造方法为new FixedLengthFrameDecoder(int frameLength, boolean allocateFullBuffer); allocateFullBuffer如果为真,则表示初始化的ChannelBuffer大小为frameLength。

(3) Delimiters

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

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

(4) DelimiterBasedFrameDecoder

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

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



即为:



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



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

maxFrameLength:解码的帧的最大长度

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

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

delimiter:分隔符
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Netty NIO Java