美文网首页netty系列程序员
深入netty之二自定义LengthFieldBasedFram

深入netty之二自定义LengthFieldBasedFram

作者: 小七赛文 | 来源:发表于2018-04-18 14:39 被阅读23次

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

    数据包协议示例1数据包协议示例1

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

    数据包协议示例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之二自定义LengthFieldBasedFram

        本文链接:https://www.haomeiwen.com/subject/lpbvkftx.html