深入netty之二自定义LengthFieldBasedFrameDecoder类

前面说到,LengthFieldBasedFrameDecoder类是我们最常用的一个粘包拆包工具,能帮我们解决95%以上的粘包拆包问题。
LengthFieldBasedFrameDecoder类能够解决的最复杂的数据包结构类似如下:

深入netty之二自定义LengthFieldBasedFrameDecoder类_第1张图片
数据包协议示例1

从上图可以看出,这种协议类似“包头1 + 包体长度 + 包头2 + 包体”这种结构。
这种协议结构已经很复杂了,但现实往往不尽如人意,比如有如下形式的数据协议:

深入netty之二自定义LengthFieldBasedFrameDecoder类_第2张图片
数据包协议示例2

这种数据协议结构类似于“包头 + 包体长度 + 包体 +包尾”。
很明显,这种带“包尾”的协议结构,就是LengthFieldBasedFrameDecoder类不能解决的。
因此,我们必须自定义这种协议的LengthFieldBasedFrameDecoder类。
我们通过对LengthFieldBasedFrameDecoder类进行预研,发现我们自定义的LengthFieldBasedFrameDecoder类不能够通过继承LengthFieldBasedFrameDecoder类来解决问题,只能把LengthFieldBasedFrameDecoder类的代码拷贝过来修改。
开始的代码如下:

public class CashboxDataLengthFieldBasedFrameDecoder extends ByteToMessageDecoder {

    private static final int TAIL_LENGTH = 7;

    private final ByteOrder byteOrder;
    private final int maxFrameLength;
    private final int lengthFieldOffset;
    private final int lengthFieldLength;
    private final int lengthFieldEndOffset;
    private final int lengthAdjustment;
    private final int initialBytesToStrip;
    private final boolean failFast;
    private boolean discardingTooLongFrame;
    private long tooLongFrameLength;
    private long bytesToDiscard;

所有的粘包拆包解码器类,都需要继承ByteToMessageDecoder类。
再往下,就是我们自定义的包尾长度-private static final int TAIL_LENGTH = 7;,后面都是拷贝LengthFieldBasedFrameDecoder类的代码。
最后的修改在decode方法里:

protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (discardingTooLongFrame) {
    discardingTooLongFrame(in);
}

if (in.readableBytes() < lengthFieldEndOffset) {
    return null;
}

int actualLengthFieldOffset = in.readerIndex() + lengthFieldOffset;
long frameLength = getUnadjustedFrameLength(in, actualLengthFieldOffset, lengthFieldLength, byteOrder);

if (frameLength < 0) {
    failOnNegativeLengthField(in, frameLength, lengthFieldEndOffset);
}

/**
 * 增加的代码,加上尾部的长度,作为内容的长度。
 */
frameLength += TAIL_LENGTH;

frameLength += lengthAdjustment + lengthFieldEndOffset;

可以看到,仅有的改动就在内容长度-frameLength上,将这个长度再加上包尾的长度,就可以了。
后面的代码,就都是考虑原LengthFieldBasedFrameDecoder类的代码了,在此就不再多说了。

你可能感兴趣的:(深入netty之二自定义LengthFieldBasedFrameDecoder类)