@Yano
2016-12-15T06:18:45.000000Z
字数 4467
阅读 3219
协议

protobuf(Protocol Buffers)是Google推出的一个结构化数据交换协议,用于传递自定义的消息格式,可用于同一台机器的进程间、不同设备进程间的数据传递。protobuf是一种语言无关、平台无关、高效、扩展性良好的语言,提供了一种将结构化数据进行序列化和反序列化的方法。
相对于XML,protobuf的体积更小、速度更快、使用更简单。我们仅需要定义一次数据结构,就可以很轻松地使用生成的代码读/写数据,而且这些数据结构是向后兼容的。
https://developers.google.com/protocol-buffers/
相对于XML来说,Protocol buffers在序列化结构化数据上,具有非常明显的优势:
如果要生成一个具有name和email的person实例,XML做法如下:
<person><name>John Doe</name><email>jdoe@example.com</email></person>
使用protocol:
# Textual representation of a protocol buffer.# This is *not* the binary format used on the wire.person {name: "John Doe"email: "jdoe@example.com"}
当此消息被编码为二进制格式时,长度大概是28字节,解析时间为100~200ns。在去除所有空格后,XML版本也至少为69字节,解析时间长达5000~10000ns。
同时,使用protocol buffer更简单:
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;
相对于JSON来说,protobuf也有明显的优势:
protobuf也有一些缺点,并不是适合所有场景。
.proto文件下面是通过Java使用protobuf的官方示例:https://developers.google.com/protocol-buffers/docs/javatutorial ,并在此基础上进行了简化。
.proto文件定义需要序列化的数据结构,为message中的每一个变量设置名称和类型。下面
package tutorial;option java_package = "yano";option java_outer_classname = "AddressBookProtos";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;}message AddressBook {repeated Person person = 1;}
my_proto.proto生成MyProto的类文件。定义字段时,我们使用了required、optional、repeated三个关键字。这些关键字表示对字段的约束,分别表示:
proto文件中的其它格式,在此不作介绍,详细内容可以参考官方文档。
现在我们有了一个.proto文件,接下来就需要将生成class文件,我们可以通过这个class文件读写AddressBook的消息。
.proto文件。
protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/addressbook.proto
通过proto编译器,addressbook.proto生成了Java类AddressBookProtos.java。每个class都有自己的Builder,用以生成该类的实例。
// required string name = 1;public boolean hasName();public String getName();// required int32 id = 2;public boolean hasId();public int getId();// optional string email = 3;public boolean hasEmail();public String getEmail();// repeated .tutorial.Person.PhoneNumber phone = 4;public List<PhoneNumber> getPhoneList();public int getPhoneCount();public PhoneNumber getPhone(int index);
Person.Builder 除了getters,还有setters方法:
// required string name = 1;public boolean hasName();public java.lang.String getName();public Builder setName(String value);public Builder clearName();// required int32 id = 2;public boolean hasId();public int getId();public Builder setId(int value);public Builder clearId();// optional string email = 3;public boolean hasEmail();public String getEmail();public Builder setEmail(String value);public Builder clearEmail();// repeated .tutorial.Person.PhoneNumber phone = 4;public List<PhoneNumber> getPhoneList();public int getPhoneCount();public PhoneNumber getPhone(int index);public Builder setPhone(int index, PhoneNumber value);public Builder addPhone(PhoneNumber value);public Builder addAllPhone(Iterable<PhoneNumber> value);public Builder clearPhone();

创建一个 Person 实例:
Person john =Person.newBuilder().setId(1234).setName("John Doe").setEmail("jdoe@example.com").addPhone(Person.PhoneNumber.newBuilder().setNumber("555-4321").setType(Person.PhoneType.HOME)).build();
以下方法能够让我们检查和操作整个message:
other的内容合并到该message中,会覆盖相同的字段,对repeated字段会添加所有的protocol buffer类都有读写二进制的方法:
OutputStreamInputStream中读取并解析message在扩展proto文件时,需要注意以下事项:
tag numbersrequired字段optional和repeated字段optional和repeated字段,但是必须使用新的tag numbers我的博客:http://www.jianshu.com/users/6835c29fc12a/latest_articles
我的知乎:https://www.zhihu.com/people/liu-jia-yu-58/activities