Netty源碼分析-ProtobufVarint32LengthFieldPrepender

ProtobufVarint32LengthFieldPrepender源碼分析

 

package io.netty.handler.codec.protobuf;

import com.google.protobuf.CodedOutputStream;
import com.google.protobuf.nano.CodedOutputByteBufferNano;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

/**
 * An encoder that prepends the Google Protocol Buffers
 * <a href="https://developers.google.com/protocol-buffers/docs/encoding?csw=1#varints">Base
 * 128 Varints</a> integer length field. For example:
 * <pre>
 * BEFORE ENCODE (300 bytes)       AFTER ENCODE (302 bytes)
 * +---------------+               +--------+---------------+
 * | Protobuf Data |-------------->| Length | Protobuf Data |
 * |  (300 bytes)  |               | 0xAC02 |  (300 bytes)  |
 * +---------------+               +--------+---------------+
 * </pre> *
 * 
 * @see CodedOutputStream
 * @see CodedOutputByteBufferNano
 */
//0xAC02 = 1010 1100   0000 0010
//varint編碼,每個字節去掉首位比特 010 1100    000 0010
//然後顛倒順序  000 0010    010 1100  = 300
@Sharable
public class ProtobufVarint32LengthFieldPrepender extends MessageToByteEncoder<ByteBuf> {

    //在發送字節前將字節長度填充在字節流前面,形成一個數據包(length+message)
    @Override
    protected void encode(
            ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
        //獲取到要發送的字節長度
        int bodyLen = msg.readableBytes();
        //根據發送字節長度,計算頭部長度需要幾個字節
        //計算方法採用GoogleProtocolBuffer 的 Base 123 VarInt 編碼方式
        int headerLen = computeRawVarint32Size(bodyLen);
        //確保out能夠存儲頭部字節長度和發送數據字節的長度。不夠out會自動擴容大小
        out.ensureWritable(headerLen + bodyLen);
        //把length採用varint編碼寫入out
        writeRawVarint32(out, bodyLen);
        //把原始消息寫入out
        out.writeBytes(msg, msg.readerIndex(), bodyLen);
    }

    //把value採用varint編碼寫入out
    static void writeRawVarint32(ByteBuf out, int value) {
        while (true) {
            //~0x7F = 1000 0000
            //寫入value的高位最後7個比特
            if ((value & ~0x7F) == 0) {
                out.writeByte(value);
                return;
            } else {
                //(value & 0x7F) = value & 01111111,把value高位全部設爲0
                // | 0x80 | 10000000 在把一個字節的第一位設爲0,這就是varint編碼規則
                out.writeByte((value & 0x7F) | 0x80);
                //把value已經輸出的7個bit移除
                value >>>= 7;
            }
        }
    }

    //根據value的大小計算需要多少個字節能夠存儲value,
    static int computeRawVarint32Size(final int value) {
        //0xffffffff <<  7) = [11111111,11111111,11111111,10000000]
        //判斷value &  [11111111,11111111,11111111,10000000] ==0
        //如果value == 0,說明value的值不錯過127
        //varint就可以用1個字節表示value
        if ((value & (0xffffffff <<  7)) == 0) {
            return 1;
        }
        //與上面邏輯一致,varint需要2個字節表示value
        if ((value & (0xffffffff << 14)) == 0) {
            return 2;
        }
        //與上面邏輯一致,varint需要3個字節表示value
        if ((value & (0xffffffff << 21)) == 0) {
            return 3;
        }
        //與上面邏輯一致,varint需要4個字節表示value
        if ((value & (0xffffffff << 28)) == 0) {
            return 4;
        }
        //與上面邏輯一致,varint需要5個字節表示value
        return 5;
    }
}

 

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