高效的序列化、反序列化工具——ProtoBuf
目录
ProtoBuf 简介
ProtoBuf(Protocol Buffers) 是 Google 用于实现序列化
与反序列化
的开源项目,支持多语言、跨平台、可扩展的用于结构化数据的解决方案。
目前常见的序列化、反序列化方法包括但不限于以下几种:
- JSON
- XML
- ProtoBuf
- Boost Serialization
ProtoBuf 数据结构
proto文件消息类型 | C++ 类型 | 说明 |
---|---|---|
double | double | 双精度浮点型 |
float | float | 单精度浮点型 |
int32 | int32 | 使用可变长编码方式,负数时不够高效,应该使用sint32 |
int64 | int64 | 同上 |
uint32 | uint32 | 使用可变长编码方式 |
uint64 | uint64 | 同上 |
sint32 | int32 | 使用可变长编码方式,有符号的整型值,负数编码时比通常的int32高效 |
sint64 | sint64 | 同上 |
fixed32 | uint32 | 总是4个字节,如果数值总是比2^28大的话,这个类型会比uint32高效 |
fixed64 | uint64 | 总是8个字节,如果数值总是比2^56大的话,这个类型会比uint64高效 |
sfixed32 | int32 | 总是4个字节 |
sfixed64 | int64 | 总是8个字节 |
bool | bool | |
string | string | 一个字符串必须是utf-8编码或者7-bit的ascii编码的文本 |
bytes | string | 可能包含任意顺序的字节数据 |
.proto
文件
关键字 | 说明 |
---|---|
syntax | 指定proto 语言版本 |
option | 修改配置选项 |
service | 声明一个服务 |
rpc | 声明一个方法 |
resturns | 方法的返回值 |
message | 定义一个消息类型 |
repeated | 数组 |
stream | 用流来交互 |
一些例子
指定一个版本
|
|
定义一个服务和方法
|
|
ProtoBuf使用一般步骤
1. 定义proto文件
proto文件中就是定义了我们需要存储或传输的数据结构/传输协议
proto文件的定义主要分为两部分:
- 为每一个需要序列化的数据结构添加一个消息(message)。
- 为消息(message)中的每一个字段(field)指定一个名字、类型和修饰符以及唯一标识(tag)。
其中每一个消息对应到C++就是一个类,嵌套消息对应的就是嵌套类。
另外,一个proto文件中可以定义多个消息,就像一个头文件中可以定义多个类一样。
|
|
- package 声明:
.proto
文件以一个package
声明开始,这个声明是为了防止不同项目之间的命名冲突,对应到 c++ 中,这个 .proto 文件生成的类将被放置在一个与package名相同的命名空间中。 - 字段类型:定义 message 时候,一个 message 就是某些类型字段的集合。具体支持的字段类型见:字段类型
- 修饰符:每个字段都必须用以下之一的修饰符来修饰:
修饰符 含义 required 必须提供字段值,否则对应的消息会被认为是" 未初始化
“的。
注意:解析"未初始化"的消息会导致失败
。optional 字段值指定与否都可以,它是每个字段默认值。
调用时候没有指定message的字段值,会自动使用默认值:string
默认值是空字符串
;int
默认值是0
repeated 字段会重复 N
次(N
可以是0
),重复值的顺序会被保存在ProtoBuf中
注意:可以把重复字段视为数组
。 - 唯一编号:每个消息中的每个字段都有唯一的编号,字段后边的
=1
、=2
等。这些字段编号用于标识消息二进制中的字段,并且在使用消息类型后不应该再更改。注意:1 ~ 15
中的字段需要一个字节进行编码,包括字段编号和字段类型。16 ~ 2047
中的字段编号需要两个字节。所以保留 1 - 15 作为非常频繁出现的消息元素,也要注意为将来可能频繁出现的消息元素预留位置。
可以指定的最小字段编号为:
1
,最大字段编号:$2^{29}-1$ 或536 870 911
。
也不能使用数字19 000
到19 999
,他们是 protobuf 保留的。
2. 编译proto文件
|
|
其中:
--cpp_out=<dir>
表示生成代码输出到的指定文件夹-I<dir>
表示在哪个文件夹下寻找 xxx.proto 文件xxx.proto
就是我们写好的.proto
文件
注意:如果编译上述例子出错,则可以重新编译安装 protobuf,几乎没有依赖,克隆源码就可编译安装。
亲测我的archlinux
使用包管理器安装的 protobuf 是不能用的。
编译 protobuf 源码具体步骤如下:
- 克隆源码:https://github.com/protocolbuffers/protobuf.git
- 进入源码目录执行安装:
./autogen.sh && ./configure --prefix=/usr && make -j8 && sudo make install
3. 使用生成的代码来读写消息
|
|
序列化与反序列化过程中尽量保证使用
char*
或std::string
来接收数据。
亲测QString参与会导致反序列化失败。