这里主要说明下面几个问题
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的值了
- 拿到