Gstyle-Protocol Buffers(protobuf)

部门内部在大行其道Gstyle—gtest、glog、protobuf。。。。。。所以我也就先学习学习,以备后面使用的时候在手慌脚乱的,上个月对gtest的使用做了一些学习,基本在日常的开发中已经开始慢慢使用了,而且我自己也根据网友的一个项目lcut分了一个分支xcut–主要是增加了一些我想要的特点。
这几天又学习了protobuf,是google的一个广泛的数据包协议,有了这个就可以把这边定义的包发送到对方,对方就可以很简单的解析出来,就类似于xml,json等协议一样,据网上说,该协议效率很高,空间占有量又很小,是一个比xml或是json要好很多的协议,但是一点就是可读性比较差,看不懂数据是怎么排列和各个字段的意思。
Protobuf的安装就不说了,主要说说使用吧,我从其源码的example中抽取了一个例子来说明一下:首先是要有一个xxx..proto的文件的,这个文件中定义你要使用的协议:这里我修改后的例子如下:(以cpp为例哦)

//xtest.proto
package xtest;
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
message PhoneNumber {
required string number = 1;
}
required PhoneNumber phone = 4;
}
message AddressBook {
repeated Person person = 1;
}

Proto注释的添加和cpp一样,用双斜杠即可。使用这样的语句将其转换为cpp文件和相应的.h文件:(前提是已经安装了Protobuf)

#ls
Makefile xtest.cc xtest.proto
#protoc –cpp_out=. xtest.proto
#ls
Makefile xtest.cc xtest.pb.cc xtest.pb.h xtest.proto
#

package xtest:表示xtest是一个命名空间,在转换后xtest.pb.cc xtest.pb.h 的文件中展现:
namespace xtest {。。。。。。
message Person:表示Person是一个类,里面的内容是其成员。在转换后的文件中以class展现。message AddressBook 也是一样的,表示Person中的一个类。可以在一个文件中添加多个message,在编译生成cpp代码后,将对应多个类。
类中成员也有其类型标签:
A.required 一个结构良好的message必须有一个这样的字段。
B.optional 结构良好的message有零个或者一个这样的字段。
C.repeated 这个字段可以重复任意多次(包括零次)。

说明:在repeated后面加上[packed = true]可以取得更高效的编码。如:repeated int32 samples = 4 [package=true]
required string name = 1:其中=1是给指定的一个标签,一个类中的标签是唯一的,在使用范围上是1~229-1,当然19000~19999是不可以使用的,因为protocol buffer内部使用。其中1~15保留为经常使用的消息元素。
对于每个成员变量,在生成xtest.pb.cc xtest.pb.h 文件后都会有相应的方法。

比如对上面的name有一下一些方法:

#include “xtest.pb.h”
int main(int argc, char* argv[]) {
GOOGLE_PROTOBUF_VERIFY_VERSION;//对protobuf使用的环境变量的初始化和对比
…………………………….
google::protobuf::ShutdownProtobufLibrary();//清场,protobuf使用的零时数据,环境变量等
return 0;
}

一下是一个对这个结构添加和读取显示的例子:(由protobuf源码中的例子修改而来)
> id;
person->set_id(id);
cin.ignore(256, ‘\n’);

cout << "Enter name: "; getline(cin, *person->mutable_name());

cout << "Enter email address (blank for none): "; string email; getline(cin, email); if (!email.empty()) { person->set_email(email);
}

cout << "Enter a phone number : "; string number; getline(cin, number); xtest::Person::PhoneNumber* phone_number = person->mutable_phone();
phone_number->set_number(number);

}

void ListPeople(const xtest::AddressBook& address_book) {
for (int i = 0; i < address_book.person_size(); i++) { const xtest::Person& person = address_book.person(i); cout << "Person ID: " << person.id() << endl; cout << " Name: " << person.name() << endl; if (person.has_email()) { cout << " E-mail address: " << person.email() << endl; } if (person.has_phone()) { const xtest::Person::PhoneNumber& phone_number = person.phone(); cout << "Phone #: " << phone_number.number() << endl; } } } int main(int argc, char* argv[]) { GOOGLE_PROTOBUF_VERIFY_VERSION; if (argc != 2) { cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl; return -1; } xtest::AddressBook address_book; { fstream input(argv[1], ios::in | ios::binary); if (!input) { cout << argv[1] << ": File not found. Creating a new file." << endl; } else if (!address_book.ParseFromIstream(&input)) { cerr << "Failed to parse address book." << endl; return -1; } } while (true) { cout << "Input 0 to finish Other continue: "; int id; cin >> id;
if (id == 0) {
break;
}
PromptForAddress(address_book.add_person());
{
fstream output(argv[1], ios::out | ios::trunc | ios::binary);
if (!address_book.SerializeToOstream(&output)) {
cerr << "Failed to write address book." << endl; return -1; } } } ListPeople(address_book); google::protobuf::ShutdownProtobufLibrary(); return 0; }

2 thoughts on “Gstyle-Protocol Buffers(protobuf)

  1. Finally, an issue that I am passionate about. I have looked for information of this caliber for the last several hours. Your site is greatly appreciated.

  2. 版主,看的还不是很明白,希望能再详细一下,真的谢谢了。我是你的站点粉丝哦,每天必来的。I love you!

Leave a Reply

Your email address will not be published. Required fields are marked *