关于 protocol buffer 的字节存储序
关于序列化
pb 报文在存储结构体中的数据时,大致上会以原始数据的每七位为一个单位,并冠以最高为 1(最低为跳过这一过程),组成一个字节,字节端序与原有数据相反,每个结构体成员还会被冠以一个 wire
来标志数据的序号和类型,大致的模型图如下:
1 2 3 |
原始数据: int64(0x81) 序列化后: wire|1000,0001|0000,0001 |
pb 整体传输的字节序顺序与结构体定义顺序一致,结构体所在的位置由 wire
的高位标识,wire
的低三位用来存储类型。为了节省容量,结构体成员都分配尽可能小的空间,一个 int64 类型 1
仅会被序列化成一个字节。
当遇见无法识别的内容时,pb 会将该数据存入 pb 字节报文的最末尾
关于反序列化
pb 在整个序列化过程中,没有记录原数据的字段名,仅用序列标识区分,故而数据反序列化时,需要盛装解析结果的结构体保持正确的接纳次序。需要主义的是,pb 本身支持的类型不见得都能被宿主语言接纳,最终类型转换的解释权归于具体的语言,譬如 golang 并没有原生的枚举类型,在解析 pb 的枚举时,超出符号范围的值会转换成 key 对应的 ascll 码:
1 2 3 4 5 6 7 8 9 10 |
// EnumName is a helper function to simplify printing protocol buffer enums // by name. Given an enum map and a value, it returns a useful string. func EnumName(m map[int32]string, v int32) string { s, ok := m[v] if ok { return s } return strconv.Itoa(int(v)) } |
关于需要注意项
- pb 关于数据会有一定的压缩处理,对传输性能会有一定的帮助
- 关于 pb 的数据类型,根据语言方的实现会略有出入,在跨语言的交互中需要注意
- 字节端序与原有数据相反
- pb 传输的字节流与结构体名无关,与顺序相关