1、linux上安装protobuf3:
1)下载:
https://download.youkuaiyun.com/download/liuxiao723846/11584862
2)编译安装:
function check_install_status() {
if [ $? -ne 0 ]; then
echo "--!!ERROR"
exit 1
fi
}
#install protobuf3
if [ ! -d protobuf-3.6.0 ]; then
tar -zxf protobuf-3.6.0.tar.gz
cd protobuf-3.6.0
./autogen.sh
./autogen.sh && ./configure
check_install_status
make -j8
check_install_status
make install
check_install_status
cd python
python setup.py install
check_install_status
ldconfig
cd ../../
fi
2、简单示例:
1)person.proto:
package test;
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
}
编译,生成C++代码:
$ protoc ./person.proto --cpp_out=./
$ ll
-rw-rw-r--. 1 roo roo 17237 Aug 20 21:19 person.pb.cc
-rw-rw-r--. 1 roo roo 12965 Aug 20 21:19 person.pb.h
2)编写C++业务代码:
#include <iostream>
#include <fstream>
#include "person.pb.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/text_format.h"
using namespace test;
int main(){
Person p;
p.set_name("test");
p.set_id(1);
p.set_email("a.iabc.com");
//------------------将pb二进制信息保存到字符串
std::string str;
p.SerializeToString(&str);
std::cout<<str<<std::endl;
//------------------将pb文本信息写入文件
std::ofstream fw;
fw.open("./Person.txt", std::ios::out | std::ios::binary);
google::protobuf::io::OstreamOutputStream *output = new google::protobuf::io::OstreamOutputStream(&fw);
google::protobuf::TextFormat::Print(p, output);
delete output;
fw.close();
//---------------------将pb文本信息保存到字符串
std::string str1;
google::protobuf::TextFormat::PrintToString(p, &str1);
std::cout<<str1<<std::endl;
//---------------------反序列化
Person p1;
p1.ParseFromString(str);
std::cout<<"name:"<<p1.name()<<",email:"<<p1.email()<<std::endl;
return 0;
}
3)编译、运行:
g++ -g -o run person_test.cpp ./person.pb.cc -I. -lprotobuf -pthread -std=c++11
或者
g++ -g -o run person_test.cpp ./person.pb.cc -I. -I/usr/local/protobuf/include -L/usr/local/protobuf/lib -lprotobuf -pthread -std=c++11
4)api说明:
- p.SerializeToString(&str):将对象p序列化成二进制数据,保存到字符串中;
- 二进制虽然小,但是可读性差,所以通过google::protobuf::TextFormat::print()方法生成文本数据写入文件;为此需要引入google/protobuf/text_format.h(否则会报‘google::protobuf::TextFormat’ has not been declared错误)、zero_copy_stream_impl.h(否则会报OstreamOutputStream找不到)
- 除了将pb信息序列化成文本写入文件外,还可以调用google::protobuf::TextFormat::PrintToString(mrlist, &str1); 方法将pb文本信息保存到字符串中;(别忘了加text_format.h头文件)
- p1.ParseFromString(str);:将字符串中的二进制信息反序列成Person对象;
- C++版pb的api一般为:pb对象.set_消息属性(value);设置属性值;pb对象.消息属性();获取属性值;
3、复杂示例:
1)pb消息结构test.proto:
syntax = "proto2";
package video_stream;
message Item{
optional string id = 1;
optional float score = 2;
}
message ModelItems{
optional string modelName = 1;
repeated Item itemList = 2;
}
message ModelRecallInfoList{
repeated ModelItems modelItemsList = 1;
}
message InnerUserPrefResponse {
optional map<string, ModelItems> user_feed_map = 1;
}
编译:
$ protoc ./test.proto --cpp_out=./
$ ll
-rw-rw-r--. 1 roo roo 55676 Aug 20 23:28 test.pb.cc
-rw-rw-r--. 1 roo roo 32236 Aug 20 23:28 test.pb.h
2)c++业务代码:
#include <iostream>
#include <fstream>
#include "test.pb.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/text_format.h"
using namespace video_stream;
int main(){
ModelRecallInfoList mrlist;
ModelItems* items;
Item* item;
//model_item1
items = mrlist.add_modelitemslist();
items->set_modelname("model_items1");
//item1
item = items->add_itemlist();
item->set_id("item1");
item->set_score(0.9);
//item2
item = items->add_itemlist();
item->set_id("item2");
item->set_score(1.2);
//model_items2
items = mrlist.add_modelitemslist();
items->set_modelname("model_items2");
//item1
item = items->add_itemlist();
item->set_id("model_item2_item1");
item->set_score(99.9);
std::string str;
mrlist.SerializeToString(&str);
//std::cout<<str<<std::endl;
std::string str1;
google::protobuf::TextFormat::PrintToString(mrlist, &str1);
std::cout<<str1<<std::endl;
//---------------------------------------反序列化
ModelRecallInfoList m;
m.ParseFromString(str);
int size = m.modelitemslist_size();
for(int i=0;i<size;i++){
ModelItems model_item = m.modelitemslist(i);
std::string model_name = model_item.modelname();
int s1 = model_item.itemlist_size();
std::string s;
for(int j = 0;j<s1;j++){
s+=model_item.itemlist(j).id()+",";
}
std::cout<<"modelName:"<<model_name<<",itemId:"<<s<<std::endl;
//std::cout<<"modelName:"<<m.modelitemslist(i).modelname()<<std::endl;
}
//---------------------------------------放到map里
InnerUserPrefResponse resp;
auto* map = resp.mutable_user_feed_map();
for (int i=0;i<size;i++){
ModelItems model_item = m.modelitemslist(i);
std::string mn = model_item.modelname();
(*map)[mn] = model_item;
}
std::string str2;
google::protobuf::TextFormat::PrintToString(resp, &str2);
std::cout<<"=========================="<<std::endl;
std::cout<<str2<<std::endl;
return 0;
}
编译、运行:
g++ -g -o run test_main.cpp ./test.pb.cc -I. -lprotobuf -pthread -std=c++11
3)api说明:
pb对象中,子对象需要使用指针;
对于repeated类型:
pb对象.add_属性名() 添加一个子对象的指针;
pb对象.属性名_size()返回repeated大小;
pb对象.属性名(i)遍历其中一个子对象;
4、复杂消息示例2:
1)student.proto
package test;
message Address {
optional string name = 1;
optional string code = 2;
}
message Student {
required string name = 1;
required int32 id = 2;
repeated string email = 3;
optional Address ads = 4;
map<string,string> other = 5;
}
编译
$ protoc ./student.proto --cpp_out=./
$ ll
-rw-rw-r--. 1 roo roo 55676 Aug 20 23:28 student.pb.cc
-rw-rw-r--. 1 roo roo 32236 Aug 20 23:28 student.pb.h
2)C++业务代码student_test.cpp:
#include <iostream>
#include "student.pb.h"
#include "google/protobuf/text_format.h"
using namespace test;
int main(){
Student p;
p.set_name("test");
p.set_id(1);
p.add_email("a.yxz.com");
p.add_email("b.abc.com");
std::string* e = p.add_email();
*e = "c.iop.com";
Address* ads = p.mutable_ads();
ads->set_name("taiyuan");
ads->set_code("0351");
auto* map = p.mutable_other();
(*map)["biye"] = "nuc";
(*map)["job"] = "abc";
//============序列化成二进制
std::string str;
p.SerializeToString(&str);
//std::cout<<str<<std::endl;
//============序列化成文本,打印
std::string str1;
google::protobuf::TextFormat::PrintToString(p, &str1);
std::cout<<str1<<std::endl;
//===========反序列化
Student p1;
p1.ParseFromString(str);
int es = p1.email_size();
std::string emails;
for (int i=0;i<es;i++){
emails += p1.email(i)+",";
}
Address adss= p1.ads();
google::protobuf::Map<std::string,std::string> o = p1.other();
google::protobuf::Map<std::string,std::string>::iterator ite;
std::string others;
for(ite=o.begin();ite!=o.end();ite++){
others+=ite->first+":"+ite->second;
}
std::cout<<"name:"<<p1.name()<<";id:"<<p1.id()<<";emails:"<<emails<<";addreds:"<<adss.name()<<";other:"<<others<<std::endl;
return 0;
}
3)说明:
- 可以看出来,对于子对象、map:设置值得时候一般需要用mutable_属性();获取值一般用属性()
- 对于pb提供的api,可以在生成的.h文件中查看相应的方法;
补充:对于map的操作:
::google::protobuf::Map< ::std::string, ::std::string >* map = test.mutable_values();
cout << "size: " << f.values_size() << endl; // size = 0
// add to map
(*map)["a"] = "a1";
(*map)["c"] = "a1";
(*map)["a"] = "a1";
cout << "size: " << f.values_size() << endl; // size = 3
也可以使用下面:
auto& map = *test.mutable_values();
map["a"] = "a1";
参考:
https://developers.google.com/protocol-buffers/docs/reference/cpp-generated#map-fields
https://www.cnblogs.com/shine-lee/p/10701810.html