这里主要说明下面几个问题
protobuf
为什么传输很快protobuf
为什么解析很快
来自于
结构说明
- json
1 | { |
- xml
1 | <id>1</id> |
- protobuf
1 | tag1tagcc |
json
和 xml
都比较熟了,就不说了,而 protobuf
是直接将值进行传递,每个值之间有一个 tag
来区分对象中不同的值。
没有字段的属性描述,自然而然,传输的数据量就小很多。
IDL(Interface Description Language)
protobuf
通常有一个单独的文件进行结构描述,比如
1 | message Person { |
无论什么语言编写,接收到来自于某一方发送来的数值,就会按照上述结构进行解析,每个字段通过一个 tag
来分割。
TAG 是什么
虽然,TAG
可以分割字段数值,但是,我们有几个疑问
TAG
是什么TAG
如何分割- 值如果和
TAG
一样的话,那么,又怎么区分呢
tag 是什么
tag
的获取方法如下
1 | static int makeTag(final int fieldNumber,final int wireType){ |
还是以下面的结构举例
1 | message Person { |
其中,方法体中的 fieldNumber
就是 1
,2
。「1
,2
可以在结构上随便赋值」
关于 wireType
是下面的选择,根据你值的类型选择不同的值。
Type | Meaning | Used For |
---|---|---|
0 | Varint | int32,int64,uint32,uint64,sint32,sint64,bool,enum |
1 | 64-bit | fixes64,sfixed64,double |
2 | Length-delimited | string,bytes,embedded message,packer repeated fields |
3 | Start group | groups(deprecated) |
4 | End group | groups(deprecated) |
32-bit | fixed32,sfixed32,float |
也就是与 000 - 010
作非运算。
tag 怎么分割
Tag
分隔符为一个字节,放置在值的前面位置。最后位置没有 tag
如果确保值与TAG 相同时,保证解析正确
Varint 编码
267
翻译成机器语言就是 00000000 00000000 00000001 00001011
我们可以发现
- 开头的
00000000 00000000
完全不需要要 - 将
00000001 00001011
翻译成10001011 00000010
- 将低位数据放到前面,并且,只取一个字节中的后
7
个bit
,将剩下的1 bit
转移到下一个字节中。 - 并且,
7 bit
中的高位bit
只有0,1
用来表示,下一个字节是否是一起的1
表示一起,0
表示下一个字节的内容是另外的字段
- 如
00000001 00001011
拆成0 0000010 0001011
将低位数据放到前面0001011 0000010 0
然后在最前面放置0
和1
,按照规则编程10001011 00000010
最后的0
是无用bit
舍去
- 将低位数据放到前面,并且,只取一个字节中的后
Zigzag 编码
考虑 -1
的编码 11111111 11111111 11111111 11111111
type | Meaning | Used For |
---|---|---|
0 | Varint | int32,int64,uint32,uint64,sint32,sint64,bool,enum |
sint32
和 sin64
是用 Zigzag
编码表示的。
原始的带符号数 | Zigzag编码后的表示 |
---|---|
0 | 0 |
-1 | 1 |
1 | 2 |
-2 | 3 |
… | … |
注意,使用 Zigzag
编码后,依然会使用 varint
进行再编码。
Tag-Length-Value
字符串。
varint
和 zigzag
都是以传输数字为基础。
如果要传输字符就要使用 Tag-Length-Value
即,TLV
。Tag
为分隔符,Length
采用 Varint
编码方式。
解析规则
- 传输一个数字
- 拿到第一个
TAG
- 解析出
filedNumber
和wireType
- 高位
1
表示下一个字节还是该数字,为0
表示下一个字节是tag
- 拿到第一个
- 传输一个字符
- 拿到
TAG
,知道下一个是字符 - 解析
Length
- 遇到
0
表示Length
已经解析完毕 - 按照长度读取字符串
- 下一个就是
TAG
的值了
- 拿到