🧱 一、Protobuf 的基本编码结构
Protobuf 的每个字段由三部分组成:
| Tag(字段编号 + 类型) | Length(长度,可选) | Value(值) |
- Tag:由字段编号(field number)和 wire type(字段类型)组成。
- Length:仅用于变长数据(如 string、bytes、嵌套消息)。
- Value:字段的实际数据。
🔢 二、Wire Type(字段类型)
Protobuf 有 6 种 wire type(字段类型),它们用 3 位二进制表示,如下所示:
| Wire Type(二进制) | 对应类型 | 说明 |
|---|---|---|
| 000 | Varint | 可变长度整数,如 int32、int64、bool、enum |
| 001 | 64-bit | 固定8字节,如 double、fixed64 |
| 010 | Length-delimited | 变长数据,如 string、bytes、嵌套消息 |
| 011 | Start group | 已弃用 |
| 100 | End group | 已弃用 |
| 101 | 32-bit | 固定4字节,如 float、fixed32 |
🔖 三、Tag 编码方式(字段编号 + wire type)
Tag 是字段编号(field number)和 wire type 的组合,使用 Varint 编码。
公式:
tag = (field_number << 3) | wire_type
例如:
- 字段编号为 3,wire type 为 Length-delimited(即 010)
(3 << 3) = 24(即二进制00011000)| 010→00011010
所以最终 tag 的二进制是:00011010
🧮 四、Value 编码详解(使用二进制)
4.1 Varint 编码(Wire Type = 000)
Varint 是一种 变长整数编码方式,小数值占用更少字节。
规则:
- 每个字节的最高位(MSB)表示是否还有后续字节:
1表示继续读下一个字节0表示结束
- 低 7 位用于存储数据(小端方式)
示例:编码整数 1000
- 1000 的二进制是:
1111101000 - 拆成 7 位一组(从低位开始):
- 第一组:
11101000(低 7 位) - 第二组:
0000011(高 7 位)
- 第一组:
- 加上 MSB:
- 第一组:
1 11101000 - 第二组:
0 0000011
- 第一组:
- 最终二进制结果是:
111101000 00000011
即两个字节:
- 第一个字节:
11110100 - 第二个字节:
00000011
4.2 Length-delimited 编码(Wire Type = 010)
用于编码字符串、嵌套消息等变长数据。
结构如下:
| Tag | Length (Varint) | Value (UTF-8 或嵌套消息) |
示例:字符串 “suc哈”
- UTF-8 编码后是:
- ‘s’ →
01110011 - ‘u’ →
01110101 - ‘c’ →
01100011 - ‘哈’ →
11100101 10010011 10001000
- ‘s’ →
- 总长度为 6 字节
- Length 为 6,Varint 编码为:
00000110(因为小于 128,所以不加 MSB)
最终编码结构(二进制):
Tag: 00011010
Length: 00000110
Value ('s'): 01110011
Value ('u'): 01110101
Value ('c'): 01100011
Value ('哈'): 11100101 10010011 10001000
📦 五、完整示例(二进制展示)
假设我们有如下 .proto 定义:
message DemoRequest {
optional string valueString = 3;
}
赋值:
valueString = "suc哈";
那么编码后的完整二进制序列如下:
00011010 // Tag: 3 + Length-delimited
00000110 // Length: 6
01110011 // 's'
01110101 // 'u'
01100011 // 'c'
11100101 // '哈' (UTF-8)
10010011
10001000
📊 六、总结对比(Protobuf vs JSON)
| 特性 | Protobuf(二进制) | JSON(文本) |
|---|---|---|
| 数据大小 | 极小(字段名用编号代替) | 较大(包含字段名、引号等) |
| 编码效率 | 高(二进制操作) | 低(字符串解析) |
| 可读性 | 不可读 | 可读 |
| 跨语言支持 | 支持多种语言 | 需要解析器 |
| 向后兼容性 | 强(支持新增字段) | 弱(需手动处理兼容) |

1948

被折叠的 条评论
为什么被折叠?



