首先,下图是常规的netty内置的protibuf编解码器的使用
本文主要介绍下面2个编解码器:
1. ProtobufVarint32LengthFieldPrepender()
对protobuf协议的的消息头上加上一个长度为32的整形字段,用于标志这个消息的长度。
这里是官方举的例子,实际这个字段的长度是5byte
(1)computeRawVarint32Size(final int value)
计算value的大小,二进制每7位为一个单位。
(2)writeRawVarint32(bodyLen)
value值是长度,0x7f的十进制值是127 (00000000 00000000 00000000 01111111),127取反得二进制(11111111 11111111 11111111 10000000)
把value和127取反的二进制进行&运算
1)只要value不大于127,则把长度写为直接写入,并直接返回。
2)如果大于127,则把value与127进行&运算,只取value二进制的低7位为1的值(其它位置0),接着把value与0x80(10000000)进行|运算,把value第8位的值变为1后写入(如果以byte类型读,则恒为负数),只取
128-
255的值。
再把value无符号右移7位,继续下一次循环
2. ProtobufVarint32FrameDecoder()
这是针对protobuf协议的
ProtobufVarint32LengthFieldPrepender()所加的长度属性的解码器
官方例子:
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
in.markReaderIndex();
// 因为length的长度为5个字节,所以申请一个5个字节的数组
final byte[] buf = new byte[5];
for (int i = 0; i < buf.length; i ++) {
//判断是否可读,不可读要重置read的索引
if (!in.isReadable()) {
in.resetReaderIndex();
return;
}
//从in里面读取数据放入数组,此时buf[i]的值有两种情况,
//(1)正数,代表当前数组i的值已经是长度二进制的最高位的值(以8个字节为单位的byte),可以进行读取。
//(2)负数,代表当前值大于127,所以在编码时与0x80(10000000)做过|运算,所以不能读取,继续进行for循环
buf[i] = in.readByte();
if (buf[i] >= 0) {
int length = CodedInputStream.newInstance(buf, 0, i + 1).readRawVarint32();
if (length < 0) {
throw new CorruptedFrameException("negative length: " + length);
}
if (in.readableBytes() < length) {
in.resetReaderIndex();
return;
} else {
out.add(in.readBytes(length));
return;
}
}
}
// Couldn't find the byte whose MSB is off.
throw new CorruptedFrameException("length wider than 32-bit");
}