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;
    }
}