Netty源碼分析-ProtobufVarint32FrameDecoder

 

 


package io.netty.handler.codec.protobuf;

import com.google.protobuf.CodedInputStream;
import com.google.protobuf.nano.CodedInputByteBufferNano;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.CorruptedFrameException;

import java.util.List;

/**
 * A decoder that splits the received {@link ByteBuf}s dynamically by the
 * value of the Google Protocol Buffers
 * <a href="https://developers.google.com/protocol-buffers/docs/encoding#varints">Base
 * 128 Varints</a> integer length field in the message. For example:
 * <pre>
 * BEFORE DECODE (302 bytes)       AFTER DECODE (300 bytes)
 * +--------+---------------+      +---------------+
 * | Length | Protobuf Data |----->| Protobuf Data |
 * | 0xAC02 |  (300 bytes)  |      |  (300 bytes)  |
 * +--------+---------------+      +---------------+
 * </pre>
 * 
 * @see CodedInputStream
 * @see CodedInputByteBufferNano
 */
public class ProtobufVarint32FrameDecoder extends ByteToMessageDecoder {

    // TODO maxFrameLength + safe skip + fail-fast option
    //      (just like LengthFieldBasedFrameDecoder)

    //根據頭部長度解碼出消息體
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
            throws Exception {
        //標記讀取下標位置
        in.markReaderIndex();
        //獲取讀取下標位置
        int preIndex = in.readerIndex();

        //根據vatint32解碼出長度信息
        int length = readRawVarint32(in);

        //如果讀取下標沒變,說明字節不夠讀取的,return等待下一輪事件
        if (preIndex == in.readerIndex()) {
            return;
        }

        //異常處理
        if (length < 0) {
            throw new CorruptedFrameException("negative length: " + length);
        }

        //還原到初始位置,因爲in裏面沒有包含length個字節,不夠讀取一個完整消息。
        if (in.readableBytes() < length) {
            in.resetReaderIndex();
        } else {
            //返回一個bytebuf,包含一個消息
            out.add(in.readRetainedSlice(length));
        }
    }

    
    //根據Google的ProtocolBuffers中的varint32解碼出長度信息
    private static int readRawVarint32(ByteBuf buffer) {
        if (!buffer.isReadable()) {
            return 0;
        }

        //標記讀取位置
        buffer.markReaderIndex();
        //讀取一個字節,如果》=0,說明字節第一個比特不是1,那麼varint編碼規則 當前值就是長度
        byte tmp = buffer.readByte();
        if (tmp >= 0) {
            return tmp;
        } else {
            //首位比特位1,後7位存儲值,保留後7位
            int result = tmp & 127;
            //不可恢復下標位置結束
            if (!buffer.isReadable()) {
                buffer.resetReaderIndex();
                return 0;
            }
            //在讀一個字節,如果第一個比特爲0,則tmp值肯定大於等於0
            if ((tmp = buffer.readByte()) >= 0) {
                //把tmp左移7位 | result 拼接爲一個整數
                result |= tmp << 7;
            } else {
                //保留7位左移 |result 拼接
                result |= (tmp & 127) << 7;
                if (!buffer.isReadable()) {
                    buffer.resetReaderIndex();
                    return 0;
                }
                //在讀一個字節,道理與上同
                if ((tmp = buffer.readByte()) >= 0) {
                    result |= tmp << 14;
                } else {
                    result |= (tmp & 127) << 14;
                    if (!buffer.isReadable()) {
                        buffer.resetReaderIndex();
                        return 0;
                    }
                    if ((tmp = buffer.readByte()) >= 0) {
                        result |= tmp << 21;
                    } else {
                        result |= (tmp & 127) << 21;
                        if (!buffer.isReadable()) {
                            buffer.resetReaderIndex();
                            return 0;
                        }
                        result |= (tmp = buffer.readByte()) << 28;
                        if (tmp < 0) {
                            throw new CorruptedFrameException("malformed varint.");
                        }
                    }
                }
            }
            return result;
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章