1.安装
在网站
http://code.google.com/p/protobuf/downloads/list上可以下载Protobuf的源代码.然后解压编译安装便可以使用
安装步骤如下所示:
tar -xzf protobuf-2.3.0.tar.gz
cd protobuf-2.3.0
./configure --prefix=~/coding/protobuf
make
make check
make install
2.例子
描述:程序由两部分组成,第一部分被称为Writer,第二部分叫做Reader.
Writer负责将一些结构化的数据写入一个磁盘文件,Reader负责从该磁盘文件中独舞结构化数据并打印到屏幕上.准备用于演示的结构化数据是HelloWorld.它包含两个基本数据:ID,为一个整数类型的数据 str:字符串
- 书写.proto文件:在protobuf术语中,结构化数据被称为Message
文件Im.helloworld.proto:
package Im;
message helloworld{
required int32 id=1;
required string str=2;
optional int32 opt=3;
}
- 编译.proto文件:写全路径
~/coding/protobuf/bin/protoc -I=/home/users/daihuan/coding/src/ -- cpp_out=/home/users/daihuan/coding/dst/ /home/users/daihuan/coding/src/Im.helloworld.proto
命令将生成两个文件,在dst目录:Im.helloworld.pb.h Im.helloworld.pb.cc
- 编写Writer和Reader
Writer将把一个结构化数据写入磁盘,以便其他人来读取.假如我们不使用Protobuf.其实也有许多的选择.一个可能的方法是将数据转换为字符串,然后将字符串写入磁盘.数字123可以编程字符串"123" .对写的人来说很简单,但是对Reader的人来讲要求很高,必须了解Writer的细节
文件Write.c:
#include <iostream>#include <fstream>#include <string>#include "Im.helloworld.pb.h"
using namespace std;int main(void){Im::helloworld msg1;msg1.set_id(101);msg1.set_str("hello");
fstream output("./log",ios::out|ios::trunc|ios::binary);
if(!msg1.SerializeToOstream(&output)){cerr << "Failed to write msg." << endl;return -1;}return 0;}msg1是一个helloworld类的对象,set_id()用来设置id的值.SerializeToOstream将对象序列化后写入一个fstream流编译:g++ -g -o Write Write.c Im.helloworld.pb.h Im.helloworld.pb.cc -I../protobuf/include -L../protobuf/lib/ -lprotobuf -lpthread
文件Reader.c
#include <iostream>
#include <fstream>
#include <string>
#include "Im.helloworld.pb.h"
using namespace std;
void ListMsg(const Im::helloworld &msg){
cout<<"msg.id="<<msg.id()<<endl;
cout<<"msg.str="<<msg.str()<<endl;
}
int main(int argc,char* argv[]){
Im::helloworld msg1;
{
fstream input("./log",ios::in | ios::binary);
if(!msg1.ParseFromIstream(&input)){
cerr<<"Failed to parse address book."<<endl;
return -1;
}
}
ListMsg(msg1);
}
同样,Reader声明类helloworld的对象msg1,然后利用ParseFromIstream从一个fstream流中读取信息并反序列化.此后,ListMsg中采用get方法读取消息的内部消息,并进行打印输出操作
g++ -g -o Reader Reader.c Im.helloworld.pb.h Im.helloworld.pb.cc -I../protobuf/include -L../protobuf/lib/ -lprotobuf -lpthread
执行./Write 和./Reader 会提示找不到lib 需要设置export LD_LIBRARY_PATH=~/coding/protobuf/lib/ 即ok
./Write 生成Log文件
./Reader
![]()
3.proto文件类型格式分析
1)定义一个消息类型:message SearchRequest{required string query=1;optional int32 page_number=2;optional int32 result_per_page=3;}A. 特定域的类型:两个整型变量page_number和result_per_page,一个string类型的变量query.也可以定义为其他类型如:枚举和 其它message类型B. 指派一个标签:这个标签是唯一的,它的范围可以是1~229-1。其中19000~19999是不可以使用的,protocol buffer内部使用。其中1~15保留为经常使用的消息元素。C. 指定字段规则:指定的消息字段的规则有以下几种:a. required 一个结构良好的message必须有一个这样的字段。b. optional 结构良好的message有零个或者一个这样的字段。c.repeated这个字段可以重复任意多次(包括零次)。说明:在repeated后面加上[packed=true]可以取得更高效的编码。如:repeated int32 samples=4 [package=true]D. 可以在一个文件中添加多个message,在编译生成cpp代码后,将对应多个类。E. proto注释的添加和cpp一样,用双斜杠即可F.运行protocol buffer编译器按照置顶的选项生成特定语言的代码,在生成的代码中包含了对proto文件中声明的变量的设定、取得、序列化消息到输出流和从输入流中分解出你的消息的操作。
2)标量值类型
3)Optional字段的默认值设定方法如:optional int32 result_per_page=3 [default=10]。 如果没有指定:string默认值为空串,bool为false,数字类型的为零,枚举类型的默认值为枚举定义列表中的第一个值.
4) Optional字段的默认值message SearchRequest{required string query=1;optional int32 page_number=2;optional int32 result_per_page=3 [default=10];enum Corpus{UNIVERSAl=0;WEB=1;IMAGES=2;LOCAL=3;NEWS=4;PRODUCTS=5;
VIDEO=6;}optional Corpus corpus=4 [default=UNIVERSAl]}外部message可以通过MessageType.EmmType取得其中的值
reference
[1]:http://www.ibm.com/developerworks/cn/linux/l-cn-gpb/
[2]:http://blog.chinaunix.net/uid-8625039-id-4430741.html
[3]:http://blog.csdn.net/eaglewood2005/article/details/4367378