此包主要作用于对TCP/IP数据包的分包和包重组,常用于数据的流传输,是扩展的解码器。
包目录结构如下:
抽象类,将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内部实现了组包的机制,不过,此时,需在数据的最前面封装整个数据的长度,示例中数据长度占了四个字节,即前四个字节是数据长度,后面的才是真实的数据。
FixedLengthFrameDecoder主要是将诸如
+----+-------+---+---+
| AB | CDEFG | H | I |
+----+-------+---+---+
此类的数据包按照指定的frame长度重新组包,比如确定长度为3,则组包为
+-----+-----+-----+
| ABC | DEF | GHI |
+-----+-----+-----+
构造方法为:new FixedLengthFrameDecoder(int frameLength);
frameLength即修正后的帧长度
另一个构造方法为new FixedLengthFrameDecoder(int frameLength, boolean allocateFullBuffer);
allocateFullBuffer如果为真,则表示初始化的ChannelBuffer大小为frameLength。
分隔符类,DelimiterBasedFrameDecoder类的辅助类。
对Flash XML的socket通信采用nulDelimiter()方法,对于一般的文本采用lineDelimiter()方法
对接收到的ChannelBuffers按照指定的分隔符Delimiter分隔,分隔符可以是一个或者多个
如将以下数据包按照“\n”分隔:
+--------------+
| ABC\nDEF\r\n |
+--------------+
即为:
+-----+-----+
| ABC | DEF |
+-----+-----+
而如果按照“\r\n”分隔,则为:
+----------+
| ABC\nDEF |
+----------+
对于DelimiterBasedFrameDecoder中的构造方法,其中一些参数说明:
maxFrameLength:解码的帧的最大长度
stripDelimiter:解码时是否去掉分隔符
failFast:为true,当frame长度超过maxFrameLength时立即报TooLongFrameException异常,为false,读取完整个帧再报异常
delimiter:分隔符