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