What are protocol buffers?
protobuf 是 protocol buffers的简称,它是结构体数据序列化的协议方法,简单、灵活、高效、自动,更重要的是它垮平台、支持多种语言(目前支持java、c++、python)。类似 XML,但是比 xml 更小、更快速、更简单。你可以一次定义特定的数据结构,然后编译生产特定的语言代码对象(例如java),然后在这种语言下你很方便的实现对这个数据结构进行读和写,并且在数据流中传输,然后实现跨语言快平台的读写操作。
How do they work?
1 按照 protobuf 的语法定义你的数据结构,保存为 .proto 文件。
例如:
message Person { required string name = 1; required int32 id = 2; optional string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { required string number = 1; optional PhoneType type = 2 [default = HOME]; } repeated PhoneNumber phone = 4; }
数据结构很简单,关于 protobuf 定义语法细节请参考:https://developers.google.com/protocol-buffers/docs/proto
一旦你定义好了你的 protobuf messages (数据结构),你可以使用 protobuf 的编译器将 .proto 文件编译生产制定语言的类文件,这个文件的成员变量和类型和 .proto 文件里面定义的对应。例如,如果你选择的是 c++ 语言,运行编译器编译上面的 .proto 文件,会生成一个叫做 Person 的类。然后你可以使用这个类进行序列化/反序列化的操作。例如:
Person person;
person.set_name("John Doe");
person.set_id(1234);
person.set_email("jdoe@example.com");
fstream output("myfile", ios::out | ios::binary);
person.SerializeToOstream(&output);
上面是将一个对象序列化写到一个输出管道中。然后再另一端你可以这样读回数据:
fstream input("myfile", ios::in | ios::binary);
Person person;
person.ParseFromIstream(&input);
cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;
图解:
为啥不用 XML 就行了
关于数据结构的序列化,protobuf 有很多优点。
- 结构更简单
- 占用空间比 XML 小3~10倍
- 速度比 XML 快10~20倍
- 比 XML更少参数歧义
- 生产语言原生数据对象更简单
例如:现在定义一个 Person 对象,包含 name 和 email 两个字段。用 XML 定义为:
<person> <name>John Doe</name> <email>jdoe@example.com</email> </person>使用 protobuf 定义为:
# Textual representation of a protocol buffer. # This is *not* the binary format used on the wire. person { name: "John Doe" email: "jdoe@example.com" }当上面的结构编码成 protobuf 的二进制格式(上面的文本格式只是为了便于人理解和调试,最终回编译成机器能理解的二进制格式)之后,上面的数据大约九占 28个字节的长度,解析速度达到100~200纳秒;而上面的 XML 格式至少占用69个字节以上,而且解析速度为5000~10000纳秒。
再看看这解析上面的便利性。protobuf 使用很简单,语言对象的使用,例如:
cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;
而 XML 的解析:
cout << "Name: "
<< person.getElementsByTagName("name")->item(0)->innerText()
<< endl;
cout << "E-mail: "
<< person.getElementsByTagName("email")->item(0)->innerText()
<< endl;
虽然 proto buf 有这么多优点,但也不是任何场合下它都比 XML 好。例如在基于文本文档模型的应用中它就不是太好用。在一个消息定义模型的应用中 protobuf 的使用意义更大。
文章参考:https://developers.google.com/protocol-buffers/docs/overview
-》下篇文章介绍 protobuf 编译器的安装。