搜索
您的当前位置:首页正文

swift Protobuf(三) 编码格式

来源:二三娱乐

这篇文章我们来分析一下Protobuf序列化后的结构,这有助于我们理解Protobuf为什么能“更小”、“更快”;

一、Protobuf的整体格式

跟Json一样,Protobuf采用的是key:value,key:value...key:value形式,如下图:


二、具体一个消息的情况

举个例子,我们定义了一个字段id:

syntax = "proto3";
message Test {
    int64 id = 1;
}

我们实例化Test,并对test.id 赋值为1,如下代码:

var test = Test()
test.id = 1

let data = try test.serializeProtobuf()
print(data.bytesStr)  // 打印出test的二进制

打印出的结果如下:

["00001000", "00000001"]

具体一个key: value的格式如下:

我们来解释一下上面的内容:
1、类型位:用来表示id字段的类型,本例中是int64,只用3bit表示字段的类型;类型位对应的含义如下图


本例中int64类型位为0;
2、指定tag:本例中是1,即id = 1中的1,所以在指定tag中二进制为"0001"
实例图中只有4位(最大值15),但实际上可以更大,此时需要msb位进行配合;
3、msb位:当msb位为1时,表示后续的 byte 也是该数字的一部分,如果该位为 0,则结束;举个栗子:test.id = 1, 所以在value部分的二进制位为"00000001",表示后面没有更多信息了;如果test.id = 128,则value部分的二进制位为"10000000" "00000001",这两个byte都是用来表示128这个值的;
读者可能会困惑,"10000000" "00000001" 是如何表示128呢,因为Protobuf字节序采用 little-endian 的方式,最终计算前将两个 byte 的位置相互交换过一次,如下图:

再举个例子,我们将id的指定tag改为99,代码如下:

int64 id = 99;

重新编译Test,运行,得到key部分的值:"10011000" "00000110",含义如下图:

从上面的分析中,我们可以看到Protobuf编码是十分紧凑的,这也是为什么Protobuf的数据量比json小的原因

Top