一种工业级结构化数据序列化方案,特性:跨语言、跨平台、体积小、版本兼容。
编码
核心:wire 格式。
消息示例:
1 | message Test1 { |
从bytes导出数据内容工具:https://github.com/protocolbuffers/protoscope/tree/main/testdata
1 | // 导出结果 |
接下来揭秘该工具如何知道消息内容的(即解码)。
Base 128 Varints
varints,即变长整数,是wire格式的核心。允许1-10byte来编码无符号64bit整数,对于较小值使用较少字节。
1 | // 1:占用1byte0000 0001 |
如何计算得出150的?
1 | 10010110 00000001 // 原始输入 |
消息结构
消息是键值对,消息二进制只使用字段编号作为key,因此字段名称无法解码得出。
编码时,每个kv都会转换为一条记录,其中包含:字段编号、wire类型、数据负载。wire类型标识了数据负载的大小,即Tag-Length-Value TLV方案。
wire类型:一共6种。
| ID | 类型 | 用于 |
|---|---|---|
| 0 | VARINT | int32, int64, uint32, uint64, sint32, sint64, bool, enum |
| 1 | I64 | fixed64, sfixed64, double |
| 2 | LEN | string, bytes, embedded messages, packed repeated fields |
| 3 | SGROUP | group start (弃用) |
| 4 | EGROUP | group end (弃用) |
| 5 | I32 | fixed32, sfixed32, float |
Tag编码:(field_number << 3) | wire_type 的变长整数,即解码时低3bit表示wire类型,其余表示字段号。
回到之前的示例:
1 | // 值1:wiretype=000 field_number=0001 |