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