格式说明及编译
test.proto
syntax = "proto2";
package tutorial;
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 phones = 4;
}
message AddressBook {
repeated Person people = 1;
}
syntax字段设置当前使用的proto版本,不设置的话会提示警告,并以默认proto2进行编译
package tutorial 英文翻译过来时包教程,反正必须在.proto文件中必须要有,否则,我这个系统没有的话会出错。
required 是必须提供的字段的值,否则该消息将被视为未初始化,如果libprotobuf在调试模式下编译,则序列化未初始化的消息将导致断言失败,在优化的构建中,将跳过检查并始终写入消息,但是,解析未初始化的消息将始终失败,通过false从解析方法中返回,除此之外,不许字段的行为,必须字段的行为与可选字段完全相同。
optional:该字段可能已经设置,也可能未设置,如果未设置该字段,则使用默认值,对于简单的类型,你可以指定自己的默认值,就像我们type在示例中为电话号码所做的那样,否则用系同默认值,数字类型为0,字符串为空字符串,bools为false。对于嵌入式的消息,默认始终是消息的默认实例或者默认原型,其中没有设置其字段。调用访问器以获取尚未显示设置的可选字段的值,始终返回该字段的默认值。
repeated:该字段可以重复任意次数(包括0).重复值的顺序将保留在协议缓冲区中,将重复字段设置为动态大小的数组。
永远必须小心的将字段标记为required。如果您希望在某个时刻停止写入或者发送必填字段。则将字段更改为可选字段会有问题,可能导致一些字段被丢弃,所以应为缓冲区编写特定于应用程序的自定义例程。使用required弊大于利,最好使用optional和repeated。
编译协议缓冲区:
协议缓冲区需要protoc命令编译后生成相应语言的代码或者包后才能被包含在要使用的程序中,在安装该写缓冲区的时候,protoc命令会安装在系统/usr/sbin目录下,所以已经设置成了环境变量。下面是编译的命令格式:
protoc --cpp_cout = $DST_DIR SRC_FILEPATH
SRC_FILEPATH:源文件绝对路径要是在源文件目录下编译的话,就可以是相对路径:)
DST_DIR:重定向生成的文件的目录
要是在当前目录下,可以更简单,我们使用上面的例子来演示:
protoc --cpp_cout = . test.proto
通过执行以上命令,会在当前目录下生成相应的.pb.cc和.pb.h文件,因为我指定的是c++语言(cpp_cout),cc文件中包含了我们在程序中需要的所有方法。
下面是一部分:
// name
inline bool has_name() const;
inline void clear_name();
inline const ::std::string& name() const;
inline void set_name(const ::std::string& value);
inline void set_name(const char* value);
inline ::std::string* mutable_name();
// id
inline bool has_id() const;
inline void clear_id();
inline int32_t id() const;
inline void set_id(int32_t value);
// email
inline bool has_email() const;
inline void clear_email();
inline const ::std::string& email() const;
inline void set_email(const ::std::string& value);
inline void set_email(const char* value);
inline ::std::string* mutable_email();
// phones
inline int phones_size() const;
inline void clear_phones();
inline const ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >& phones() const;
inline ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >* mutable_phones();
inline const ::tutorial::Person_PhoneNumber& phones(int index) const;
inline ::tutorial::Person_PhoneNumber* mutable_phones(int index);
inline ::tutorial::Person_PhoneNumber* add_phones();
标准消息方法
每个消息还包含许多其他方法,可用于检查或操作整个消息,包括:
- bool IsInitialized() const :检查是否设置了所有必填字段。
- string Debugstring() const :返回消息可读表示,用于调试。
- void CopyFrom(const Person&from):使用给定消息的值覆盖消息。
- void Clear():清空所有元素为空的状态。
解析和序列化
最后,每个协议缓冲区类都是用协议缓冲区二进制格式编写和读取所选类型消息,这些包括:
- bool serialize toString(string * output) const :序列化消息并将字节存储在给定的字符串中,注意,字节是二进制,不是文本,我们只修改string 类用作方便的容器。
- bool ParseFromString(const string& data) :解析给定字符串中的消息。
- bool SerializeToOstream(ostream*output) const :将消息写入给定的c++ ostream。
- bool ParseFromIstream(istream* input) :解析来自c++的istream。
使用
syntax = "proto2" ;
package Messages ;
//命令的值
message Value {
repeated string val = 1;
}
message Command {
//命令
required string cmd = 2;
//命令长度
required int32 len = 3 ;
//命令的键
required string key =4 ;
repeated Value vals = 5;
}
使用protoc编译上面代码,生成.pb.cc和.pb.h文件。
#include <iostream>
#include "stringOperation.h"
#include "serializeParse.h"
#include "msg.pb.h"
using namespace std ;
using namespace Messages ;
int main() {
string com ;
vector<string>ls = split(com, " ");
int len = ls.size() ;
Command cmd ;
string aa = "";
cmd.set_cmd("get") ;
cmd.set_key("name") ;
cmd.set_len(10) ;
Value* val = cmd.add_vals() ;
//设置值,值可能重复
for(int i=2; i<len; i++) {
string* a = val->add_val() ;
*a = ls[i] ;
cout << *a << endl ;
}
string aaa ;
✗ cmd.SerializeToString(&aaa) ;
//发序列化
Command cmm ;
✗ cmm.ParseFromString(aaa) ;
cout << "cmd:" << cmm.cmd() << endl ;
cout << "key:" << cmm.key() << endl ;
len = cmm.vals_size() ;
for(int i=0; i<len; i++) {
int a = cmm.vals(i).val_size() ;
for(int j=0; j<a; j++) {
cout << "value :" << cmm.vals(i).val(j) << endl;
}
}
cout << "len:" << cmm.len() << endl ;
cout << "结束" << endl ;
return 0;
}
我的Ubuntu18.10编译以上代码:
g++ msg.pb.cc main.cpp -o main -lprotobuf `pkg-config --cflags --libs protobuf`
结果:
以上以序列化string座位例子,还可以序列化文件流等更多高级的操作。详细教程见官方文档C++: