netty源码分析之LengthFieldBasedFrameDecoder

复制代码
 1 /**
 2      * Creates a new instance.
 3      *
 4      * @param byteOrder
 5      *        the {@link ByteOrder} of the length field
 6      * @param maxFrameLength 包的最大长度
 7      *        the maximum length of the frame.  If the length of the frame is
 8      *        greater than this value, {@link TooLongFrameException} will be
 9      *        thrown.
10      * @param lengthFieldOffset 长度域的偏移量
11      *        the offset of the length field
12      * @param lengthFieldLength 长度域长度
13      *        the length of the length field
14      * @param lengthAdjustment 包体长度调整的大小(可以为负数)
15      *        the compensation value to add to the value of the length field
16      * @param initialBytesToStrip 跳过(忽略)的字节数
17      *        the number of first bytes to strip out from the decoded frame
18      * @param failFast
19      *        If <tt>true</tt>, a {@link TooLongFrameException} is thrown as
20      *        soon as the decoder notices the length of the frame will exceed
21      *        <tt>maxFrameLength</tt> regardless of whether the entire frame
22      *        has been read.  If <tt>false</tt>, a {@link TooLongFrameException}
23      *        is thrown after the entire frame that exceeds <tt>maxFrameLength</tt>
24      *        has been read.
25      */
26     public LengthFieldBasedFrameDecoder(
27             ByteOrder byteOrder, int maxFrameLength, int lengthFieldOffset, int lengthFieldLength,
28             int lengthAdjustment, int initialBytesToStrip, boolean failFast) {
29         if (byteOrder == null) {
30             throw new NullPointerException("byteOrder");
31         }
32 
33         checkPositive(maxFrameLength, "maxFrameLength");
34 
35         checkPositiveOrZero(lengthFieldOffset, "lengthFieldOffset");
36 
37         checkPositiveOrZero(initialBytesToStrip, "initialBytesToStrip");
38 
39         if (lengthFieldOffset > maxFrameLength - lengthFieldLength) {
40             throw new IllegalArgumentException(
41                     "maxFrameLength (" + maxFrameLength + ") " +
42                     "must be equal to or greater than " +
43                     "lengthFieldOffset (" + lengthFieldOffset + ") + " +
44                     "lengthFieldLength (" + lengthFieldLength + ").");
45         }
46 
47         this.byteOrder = byteOrder;
48         this.maxFrameLength = maxFrameLength;
49         this.lengthFieldOffset = lengthFieldOffset;
50         this.lengthFieldLength = lengthFieldLength;
51         this.lengthAdjustment = lengthAdjustment;
52         lengthFieldEndOffset = lengthFieldOffset + lengthFieldLength;
53         this.initialBytesToStrip = initialBytesToStrip;
54         this.failFast = failFast;
55     }
复制代码

示例:

|p_h|len|cmd|data|sum|p_t|  len是整个包长度
socketChannel.pipeline().addLast("lengthFieldBasedFrameDecoder", new LengthFieldBasedFrameDecoder(14, 1, 1, -2, 0));
复制代码
 1 /**
 2      * Create a frame out of the {@link ByteBuf} and return it.
 3      *
 4      * @param   ctx             the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to
 5      * @param   in              the {@link ByteBuf} from which to read data
 6      * @return  frame           the {@link ByteBuf} which represent the frame or {@code null} if no frame could
 7      *                          be created.
 8      */
 9     protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
10         if (discardingTooLongFrame) { //丢弃模式
11             discardingTooLongFrame(in);
12         }
13 
14         if (in.readableBytes() < lengthFieldEndOffset) { //如果当前可读字节还未达到长度域的偏移,那说明肯定是读不到长度域的,直接不读
15             return null;
16         }
17 
18         int actualLengthFieldOffset = in.readerIndex() + lengthFieldOffset; //通过当前读索引+长度域偏移量,获取长度域的实际字节索引
19         long frameLength = getUnadjustedFrameLength(in, actualLengthFieldOffset, lengthFieldLength, byteOrder); //通过长度域的实际字节索引和长度域长度,获取实际包长度
20 
21         if (frameLength < 0) {
22             failOnNegativeLengthField(in, frameLength, lengthFieldEndOffset);
23         }
24 
25         frameLength += lengthAdjustment + lengthFieldEndOffset; //调整包长度,如果长度是指整个包的长度,lengthAdjustment为lengthFieldEndOffset的负数;如果长度是指包内容大小,lengthAdjustment设置为0。ps:数据包是否需要调整需要看具体业务(lengthFieldEndOffset = lengthFieldOffset + lengthFieldLength)
26 
27         if (frameLength < lengthFieldEndOffset) {
28             failOnFrameLengthLessThanLengthFieldEndOffset(in, frameLength, lengthFieldEndOffset);
29         }
30 
31         if (frameLength > maxFrameLength) { //长度大于最大长度时,判断是直接丢弃数据还是进入丢弃模式
32             exceededFrameLength(in, frameLength);
33             return null;
34         }
35 
36         // never overflows because it's less than maxFrameLength
37         int frameLengthInt = (int) frameLength;
38         if (in.readableBytes() < frameLengthInt) { //可读字节数小于长度,直接不读,等待下次读取
39             return null;
40         }
41 
42         if (initialBytesToStrip > frameLengthInt) { //需要跳过的字节数大于长度,报错
43             failOnFrameLengthLessThanInitialBytesToStrip(in, frameLength, initialBytesToStrip);
44         }
45         in.skipBytes(initialBytesToStrip); //跳过指定字节数
46 
47         // extract frame
48         int readerIndex = in.readerIndex(); //当前累积数据的读指针
49         int actualFrameLength = frameLengthInt - initialBytesToStrip; //拿到待抽取数据包的实际长度
50         ByteBuf frame = extractFrame(ctx, in, readerIndex, actualFrameLength); //抽取数据包
51         in.readerIndex(readerIndex + actualFrameLength); //移动读指针
52         return frame;
53     }
复制代码

 

判断是直接丢弃数据还是进入丢弃模式

复制代码
 1 private void exceededFrameLength(ByteBuf in, long frameLength) {
 2         long discard = frameLength - in.readableBytes(); //包长度与可读字节数比较
 3         tooLongFrameLength = frameLength;
 4 
 5         if (discard < 0) {
 6             // buffer contains more bytes then the frameLength so we can discard all now
 7             in.skipBytes((int) frameLength); //可读字节数大,直接丢弃包长度,剩下的可能是个合法数据包
 8         } else {
 9             // Enter the discard mode and discard everything received so far.
10             discardingTooLongFrame = true; //包长度大,进入丢弃模式
11             bytesToDiscard = discard; //剩余需要丢弃的字节长度
12             in.skipBytes(in.readableBytes()); //跳过可读字节数
13         }
14         failIfNecessary(true); //判断是否需要抛出异常
15     }
复制代码

 

丢弃模式

复制代码
1 private void discardingTooLongFrame(ByteBuf in) {
2         long bytesToDiscard = this.bytesToDiscard;
3         int localBytesToDiscard = (int) Math.min(bytesToDiscard, in.readableBytes()); //需要丢弃的字节长度与可读字节数获取最小值
4         in.skipBytes(localBytesToDiscard); //跳过字节
5         bytesToDiscard -= localBytesToDiscard; //获取剩余需要丢弃的字节数
6         this.bytesToDiscard = bytesToDiscard;
7 
8         failIfNecessary(false);
9     }
复制代码

 

判断是否需要抛出异常

复制代码
private void failIfNecessary(boolean firstDetectionOfTooLongFrame) {
        if (bytesToDiscard == 0) { //需要丢弃字节数为0时,退出丢弃模式
            // Reset to the initial state and tell the handlers that
            // the frame was too large.
            long tooLongFrameLength = this.tooLongFrameLength;
            this.tooLongFrameLength = 0;
            discardingTooLongFrame = false;
            if (!failFast || firstDetectionOfTooLongFrame) {
                fail(tooLongFrameLength);
            }
        } else {
            // Keep discarding and notify handlers if necessary.
            if (failFast && firstDetectionOfTooLongFrame) { //failFast默认true
                fail(tooLongFrameLength); //报错
            }
        }
    }
复制代码

 

 参考:

netty源码分析之LengthFieldBasedFrameDecoder - 简书 (jianshu.com)

posted @   顾满楼  阅读(225)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示