最近领导分配了一个任务,这个工程挺高端的,主要以前从没有搞过,其中里面有protobuf,以前从来没有听说过这个东西,最近在网上看了一些高人的帖子,才知道protobuf是什么云云了,我的理解是,例如我们要用C++写个什么工程,C++是面向对象的,我们要写很多类,估计都得写上上百行,上千行的代码,但是现在用这个protobuf,就可以省很多是,我们只需要写消息包,然后编译,protobuf就会根据这个消息包自动生成两个文件.cc.h.h这两个文件中就有很多类,供我们调用。
现在说明怎样在Ubuntu下安装protobuf。网上有人说,他用了很多版本的protobuf都没有成功,最终用的2.5.0版本才成功,于是我就直接安装了这个版本,至于其他版本成不成功,我就不知道了。首先下载protobuf源码包
在Ubuntu的终端里输入:$  wget lecode/files/protobuf-2.5. 
这是在下载,但是我等了很长时间都没有下载下来,最后我在CSDN上下载下来了
下载之后解压: $  tar xvzf protobuf-2.5.  
进入到解压后的目录: $  cd protobuf-2.5.0
进行执行 :  $  ./configure   
在执行./configure这个命令之前最好把vim ,g++,make安装好,不然在执行./configure的时候可能会出现错误,上面三个安装的命令:$sudo apt-get install vim  $sudo apt-get install g++    $sudo apt-get install make 
./configure成功之后,接下来是如下几步:
$make
$make check
$make install     //在执行这一步的时候,我出现了错误,错误的意思是执行的权限不够,如果是这样的话,$make install  这条命名就换成$sudo make install
下面我们要修改一下配置文件:$ vim  ~/.profile
在打开的文件中,在文件末尾添加如下代码:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
    然后保存退出,接下来执行:    $ source  ~/.profile
使刚才修改的配置文件生效,接下来执行: $protoc --version
如果上面的步骤一切顺利的话,那么就会在终端显示protobuf的版本号,如下
下面我们来测试一下,在测试之前我们最好先建立一个文件夹,例如上面的proto,接下的操作都在这个文件夹下进行。
我们先用vim创建并编辑.proto文件,例如:vim msg.proto
内容如下:
然后执行下面的命令: $ protoc -I=.  --cpp_out=.  msg.proto
执行这条命名之后,在当前目录下就会生成如下的两个文件:
这两个文件就是根据上面的那个msg.proto文件生成了,里面有类的声明和类的实现,我们可以进入这两个文件。研究一下,这里就不在说明了。然后我们就可以调用类和里面的函数实现自己的功能了,下面是两个简单的测试文件:
我们先创建: $ 
内容如下:
然后编译,命名如下:
$ g++  -o write  `pkg-config --cflags --libs protobuf` -lpthread
执行生成的write文件,命令为:
$ ./write
可看到生成的msg.pb文件,这个文件是由fstream output(“./msg.pb”,ios::out|ios::trunc|ios::binary)函数生成的
下面在创建一个文件:$
内容如下:
编译文件:命令为:
$ g++  -o reader  `pkg-config --cflags --libs protobuf` -lpthread
然后执行生成的reader文件。命令如下:
./reader
在终端就会打印出:
101
Hello
上面在生成可执行文件的过程,都是我们一条一条命令的输入,我们可以写Makefile,然后执行一条make命令,就可以自动生成可执行文件,
编写Makefile文件: $ vim Makefile
内容如下:
编写完之后,执行:$make
就会自动生成可执行文件writereader
Protobuffer语言详解:
Defined A Message Type
message SearchRequest
{   
required string query = 1;
oprional int32 page_number = 2;
optional int32 result_per_page = 3;
}
上面 SearchRequest消息定义了三个fileds,每一个fileds都包含着该filednametype Message里面的每一个field都有一个unique numbered tag(也就是那些1 2 3 4)。这些tags用来在message binary format用来标识filed序号,如果这个message一旦被使用,建议必要轻易更改。需要注意的是,如果标记是1-15,那么当标记编码成二进制流的时候他们仅占一个字节,如果标记处于16-2047,标记将会占据两个字节,所以这里建议,对于那些需要频繁传输的数据尽量把他们放在前15位,这时编码key的时候就会尽量减少key的数据的大小,那么我们也应该留一些15因内的标记,以便将来可能会添加更频繁使用的filed
最小的标记是1,最大的是2^29-1,但是从1900019999这些被protobuf 实现保留。
Specifying Field Rules
你必须声明你所声明的filed是如下一种:
required:在你使用该消息时必须存在这种类型的filed
optional:在你使用该消息时该中filed可以不存在,但如果存在的只能存在一种
repeated:该中类型的filed可以被重复使用任意从(包括0),而且protobuf会保存设置的次序。
Adding more message types
在一个.proto文件中可以定义多个message。例如你想定义多个相关联的message,如下例在一个proto文件中有一个reques message和一个reponse message
message SearchRequest
{
    required string query = 1;
    optional int32 page_number = 2;
    optional int32 result_per_page = 3;
}
message SearchResponse
{
    ……
}
我们可以直接使用//.proto文件中添加注释
message SearchRequest
{
    required string query = 1;
    optional int32 page_number = 2; //which page number do we want?
    optional int32 result_per_page = 3;
}
What's Generated From Your .proto?
当我们使用protocol buffer compiler编译一个.proto文件,编译器会生成与你所选语言(由编译选项决定--Java_Out 或者--Cpp_Out)相对应的代码。例如会生成所有字段的getter/setter,向输出流序列化你的messages以及从一个输入流中解析messages
For C++,,编译器会生成一个 .h .cc文件, proto文件里每一个message都会对应生成一个class.
For Java,编译器会生成一个java文件.在该java文件中会有N个由messages对应生成的内部类,以及一个Builder内部类.Builder用来创建其他messages生成的类的实例
Optional Fields And Default Values
如果一个optional field已经被手动地设置过默认值,那么在解析该messages时,发现该field没有被使用,那么该field会被设置成默认值.如下例
optional int32 result_per_page = 3 [default = 10];
那么如果没有手动地被设置过默认值那么就会采用系统默认值:string->"", bool->false, numeric->0 ,enums ->enums第一个value的默认值
Enumerations
message中,可以使用枚举。Protobuf中的枚举以name/value形式出现。例如下例:VNIVERSAL = 0messages什么意思可以看出其value不是field_number
你可以对一个枚举类型的filed指定默认值,但是如果你指定的的值不在枚举列表中,那么解析器会认为这个字段为不可识别的字段。
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];
}
Using Other Message Types
我们可以采用其他的message作为我们的field类型.例如在下例中我们在同一.proto文件中定义了俩个messages,然后SearchResponse中使用Result作为field的类型.

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。