AUTHOR: Locez
VERSION: 1
1 Protocol Buffers 是什么?
Protocol Buffers 是 google 开发的一种开源的、跨平台的、可扩展的结构化数据序列化机制。使用 Protocol BUffers 可以定义只定义一次结构化的数据,然后通过生成的代码,在各种语言的数据流中都可以轻松高效的读取和写入定义好的结构化数据。
注: 因代码仓库名称为 protobuf,以下为了行文简单, 统一使用 protobuf 指代 Protocol Buffers
1.1 Protobuf 的优势是什么?
Protobuf 是一种结构化的,序列化和反序列化的机制,那么对比最常用的 json、 xml 有什么优势呢?
- 序列化与反序列化执行效率高
- 序列化产物较小,在网络传输中可以更加节省带宽
- 支持直接生成各种语言的代码,访问接口统一舒适
一个基本的 proto 文件中的结构体定义如下(proto2 语法):
1 | message Person { |
可以看到结构体中定义了字段的类型和名字,以及字段的对应的唯一的编号。其中编号用来定位在二进制数据中,字段的位置,所以一个结构体一旦使用了,就不应该再被更改。因为 protobuf 使用编号定位字段,所以序列化的时候不会带上 key,只会有 value,这就使得序列化产物非常小。通常 1 到 15 号用来标识一些比较频繁出现的数据。
相对应地,一个 json 字符串如下:
1 | { |
上述的字符串就是 json 序列化后的产物,可以看到, json 序列化时会带上 key,使得序列化产物比 protobuf 大的多( xml 同理),其次就是类似于 json 这种高度可读的数据,并没有保存数据的类型,在解析的时候,需要不断的判断或断言,找到正确的数据类型,然后绑定到这个数据类型上面去,而 protobuf 在序列化的时候会带入数据类型,从而提高它在反序列化时的效率。
2 安装 protobuf
要使用 protobuf,首先需要生成 protobuf 目标语言的源代码,protobuf 提供了一个名为 protoc 的二进制程序,用来生成目标语言源代码。
Gentoo
1 | # emerge --ask protobuf |
Ubuntu
1 | # apt-get install libprotobuf-dev protobuf-compiler |
Arch
1 | # pacman -S protobuf |
2.1 protoc
使用 protoc 来生成目标语言的源代码, 主要使用的参数有两个:
- -I 指定 proto 文件的搜索更目录,当在一个 proto 文件中使用相对路径 import 了另一个 proto 文件时,使用 -I 配置搜索的根目录
- –language_out=dir 生成目标语言的代码,且存放到 dir 中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20$ protoc --help
Usage: protoc [OPTION] PROTO_FILES
Parse PROTO_FILES and generate output based on the options given:
-IPATH, --proto_path=PATH Specify the directory in which to search for
imports. May be specified multiple times;
directories will be searched in order. If not
given, the current working directory is used.
If not found in any of the these directories,
the --descriptor_set_in descriptors will be
checked for required proto file.
...
...
--cpp_out=OUT_DIR Generate C++ header and source.
--csharp_out=OUT_DIR Generate C# source file.
--java_out=OUT_DIR Generate Java source file.
--js_out=OUT_DIR Generate JavaScript source.
--objc_out=OUT_DIR Generate Objective-C header and source.
--php_out=OUT_DIR Generate PHP source file.
--python_out=OUT_DIR Generate Python source file.
--ruby_out=OUT_DIR Generate Ruby source file.
3 protobuf 使用实战
接下来,将使用 cpp
进行一些 protobuf 使用的实战,演示 protobuf 的能力
项目结构主要如下:
1 | ~/protobuf-examples |
生成 cpp 代码的命令如下:
1 | $ protoc -I ./proto/ --cpp_out=cpp/proto proto/* |
为了便于工程上的管理,本文的 example 最终采用 cmake 构建,项目结构如下, 生成 cpp 文件的操作在 CMakeLists.txt 中完成
1 | ~/protobuf-examples |
3.1 protobuf 读写、序列化与反序列化
该 example 的 proto 文件如下:
1 | syntax = "proto2"; |
Protobuf 所生成的 cpp 代码,以 object.set_variable(value) 的形式进行赋值操作,以 object.variable() 的形式进行访问
1 |
|
输出如下:
1 | ./bin/read_write |
3.2 Protobuf 与 json 的互相转换
protobuf 提供了与 json 互相转换的能力,以便于更好的在各种系统之间共享数据
proto 文件如下:
1 | syntax = "proto3"; |
protobuf 提供了一些序列化选项和反序列化选项,用来影响与 json 转换的具体行为,具体的例子如下:
1 |
|
输出如下:
1 | ./bin/pb2json |
总结
未完待续
参考资料
- 本文代码仓库-protobuf_examples,文中的所有示例代码都可以在此找到