google protocol buffers介绍(c++)
来源:互联网 发布:问卷调查数据分析报告 编辑:程序博客网 时间:2024/05/21 09:18
ref:http://blog.csdn.net/learnhard/archive/2010/09/04/5863846.aspx
源码:http://code.google.com/p/protobuf/downloads/list
1.什么是googleprotocol buffer
(略)
2.proto文件格式介绍:
注释:使用//
package:名字空间
message:类似一个class/struct,格式:message{…;}
字段修饰符:required---必需字段,否则对应的message“未初始化”,debug模式下导致断言,release模式下解析失败;optional---可选字段,不指定,使用默认值(数据类型0/string空/bool为false/嵌套message默认构造/枚举为第一个);repeated---重复字段,可看作是动态数组,在编码时,应该使用特殊选项[packed=true]来保证更高效的编码。
支持类型:
.proto type
c++
notes
double
double
float
float
int32
int32
使用可变长编码方式,负数时不够高效,应该使用sint32
int64
int64
同上
uint32
uint32
使用可变长编码方式
uint64
uint64
同上
sint32
int32
使用可变长编码方式,有符号的整型值,编码时比通常的int32高效
sint64
sint64
同上
fixed32
uint32
总是4个字节,如果数值总是比2^28大的话,这个类型会比uint32高效
fixed64
uint64
总是8个字节,如果数值总是比2^56大的话,这个类型会比uint64高效
sfixed32
int32
总是4个字节
sfixed64
int64
总是8个字节
bool
bool
string
string
一个字符串必须是utf-8编码或者7-bit的ascii编码的文本
bytes
string
可能包含任意顺序的字节数据
tag:”=1”/”=2”指出该字段在二进制编码中使用的唯一tag。tag在1-15编码所需的字节数比更大的标志号使用的字节要少1个。重复字段中,每一项都要求重新编码tag,所以重复字段最好使用1-15的tag号。
默认值:对于required/optional字段,可以使用[default=xxx];指定默认值
3.认识源码
下载源码包:http://code.google.com/p/protobuf/downloads/list
editors:这里只是编辑时需要的插件,比如在vim中,添加代码高亮显示:~/.vimrc添加soproto.vim
examples:里面有个通讯录的例子
src:protoc的源码,也就是一个小的语法解析器和代码生成器。主要用途就是从proto文件生成需要的代码。(当然,也可以安装protobuf-compiler包,直接安装protoc)
使用过程:编译源码包,在protobuf-2.3.0/src目录下,会生成上面所说的protoc工具。进入examples目录,../src/protoc--cpp_out=./ addressbook.proto,当然,可以先makeinstall安装protoc,而不用使用相对路径。现在,应该有addressbook.pb.h/addressbook.pb.cc生成。编译:g++add_person.cc addressbook.pb.cc -I../src/ -lprotobuf -L../src/.libs/-lpthread-Wl,-rpath=../src/.libs/即可。注意:在使用protoc指定源文件/目标目录时,都需要使用绝对路径。
关于代码生成:
required/optional:均有has_xx、clear_xx、tag号、set_xx、xx、mutable_xx等方法生成。xx返回引用,mutable_xx返回指针,但对数值类型没有后者,前者也只是返回副本。
repeated:包括xx_size、clear_xx、tag号、xx(i)、mutable_xx(i)、add_xx(返回指针)、xx()(返回整个)、mutable_xx()(返回整个)
所有生成的类,均继承自message(protobuf-2.3.0/src/google/message.h):
IsInitialized()---检查全部的required字段是否都被set了值
DebugString()---调试时,返回一个易读的消息表示形式
CopyFrom(Message&from)---使用外部消息的值,覆盖调用者消息内部的值
Clear()---将所有项复位到空状态
SerializeToString(string*output)---将消息序列化,并存储在指定的string中。注意里面的内容是二进制的,我们只是使用string作为一个很方便的容器。
ParseFromString(conststring& data)---从给定的string解析消息
SerializeToOstream(ostream*out)---将消息写入给定的ostream中
ParseFromIstream(istream*input)---从给定的istream中解析消息
更多的api见:http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/reference/cpp/index.html
4.我们需要做什么
1.搞定proto文件
2.使用protoc工具生成需要的代码
3.使用生成的代码编写程序
编写过程中需要注意:
1.在使用c++protocolbuffer库之前先执行GOOGLE_PROTOBUF_VERIFY_VERSION宏。检查链接的库文件和头文件是否兼容。
2.在程序结尾处调用google::protobuf::ShutdownProtobufLibrary(),删除由protocolbuffer库分配的全局对象。
3.链接库:-lprotobuf
4.枚举常量必须在32位整型值范围内,因为enum值是使用可变长编码方式,对负数不够高效,不推荐enum中使用负数。
5.导入定义:import"myproject/other_protos.proto";//-I/-import_path指定,不提供就在调用目录下查找。
6.组的概念已经被弃用了,应使用嵌套消息类型来代替它。
7.关于扩展:1)对于已经存在的任何字段,不可修改tag;2)不能添加或删除任何required字段;3)可以添加optional/repeated字段,但是tag必须使用新的;4)非required字段可以移除,但tag号仍然保留,不可重用;5)可以添加optional/repeated字段,但是tag必须使用新的
;对于老代码,会忽略掉任何新的字段,已经被删除的optional字段将被赋予默认值,已经被删除的repeated字段将为空。新代码也能透明的读取旧的消息。新的optional字段将不会出现在旧的消息中。如果添加了一个新的repeated字段,新的代码将无法告诉你它是否被留空了(被新代码),或者是否从未被set值(被旧代码),因为它没有has_标志;6)一个非required字段可以转换为一个扩展,反之亦然—只要它的类型和tag号保持不变;
8.关于兼容:1)int32/uint32/int64/uint64/bool是全部兼容的,类似强制转换;2)sint32/sint64是互相兼容的,但是它们与其他整数类型不兼容;3)string和bytes兼容—只要bytes是有效的utf-8编码;4)嵌套消息和bytes兼容--只要bytes包含该消息的一个编码过的版本;5)fixed32和sfixed32兼容,fixed64和sfixed64兼容
5.关于优化
1.尽可能重复利用message对象。但是,当消息大小不一致时,可以通过调用SpaceUsed函数监测消息对象的大小,并在它太大的时候删除它。
2.多线程中分配大量小对象时,可以尝试使用google'stcmalloc
6.关于技巧
将多个消息转化为流:protoc解析器无法自己决定一个消息结束于何处。所以:在写入每一个消息之前,先写入消息的大小。
大数据集:protocolbuffers不是设计来处理大消息的。如果单条消息大于1M,则……
联合类型:处理多种类型的消息
自描述的消息:对于原始消息,没有proto文件的情况下,可以通过使用-descriptor_set_out选项+google/protobuf/descriptor.proto+一个自描述的协议消息(见官方网站)+DynamicMessage类来解析该原始消息。
7.关于其他
7.1 extensions:
messageFoo{extensions 100 to 199;}//不可更改文件
extend Foo {optional int32 bar =126;}//外部增加bar字段给Foo消息
Foo foo; foo.SetExtension(bar,15);//这样的字段具有特殊的访问函数
类似,Foo类也生成了模板函数Has/Clear/Get/Mutable/AddExtension。
7.2 NestedExtensions:
messageBaz{extend Foo{optional int32 bar = 126;}}
Foo foo;foo.SetExtension(Baz::bar, 15);
在一个消息类型中嵌套声明一个extend块并没有暗示外部类型与扩展类型之间有任何联系。特别地,上面的例子并没有表明Baz是Foo的任何类型的子类。它所表明的仅仅是:符号bar只是再Baz的内部声明的;它只是一个静态成员罢了。
7.3 风格:
消息名/枚举名---每个单词首字母大写,字段名---小写下划线,枚举值---大写下划线
- google protocol buffers介绍(c++)
- Google Protocol Buffers介绍
- 【Protocol Buffers】Google开源技术-Protocol Buffers介绍
- Google Protocol Buffers(转载)
- Google Protocol Buffers介绍和总结
- Google Protocol Buffers介绍和总结
- Google Protocol Buffers介绍和总结
- Google Protocol Buffers介绍和总结
- Protocol Buffers 介绍(一)
- Protocol Buffers 介绍(二)
- Google Protocol Buffers浅析(一)
- Google Protocol Buffers浅析(二)
- Google Protocol Buffers浅析(三)
- Google Protocol Buffers浅析(四)
- Google Protocol Buffers浅析(一)
- Google Protocol Buffers浅析(二)
- Google Protocol Buffers浅析(三)
- Google Protocol Buffers浅析(四)
- 创建一个filter实例
- Mysql数据库做多台replication
- 80个电脑常识全是你平时上网用的着的!
- 早晨琐事
- 设计模式之观察者模式 【转】
- google protocol buffers介绍(c++)
- 转WaveOutSetVolume
- 她拒绝了他100次,但第101次他拒绝了她!
- magento获取指定目录分类的子分类
- Type.GetType(string typeName) returns null !?
- 监听用户电话状态
- 介绍一个Android开源项目:GifView——Android显示GIF动画
- Java 5.0 Thread
- subversion安装及使用