1. pb文件
syntax = "proto3"; // syntax 版本2/3是不一样,默认是proto2
package IM.Login; // package 生成对应的C++命名空间 IM::Login::
import "IM.BaseDefine.proto"; // import 引用其他proto文件
option optimize_for = LITE_RUNTIME;
// message关键字 代表一个对象
message Phone{
string number = 1; // = 1是什么?默认值
IM.BaseDefine.PhoneType phone_type = 2;
}
message Book{
string name = 1;
float price = 2;
}
message Person{
string name = 1;
int32 age = 2;
repeated string languages = 3;
Phone phone = 4;
repeated Book books = 5; // repeated 重复, 可以嵌套对象
bool vip = 6;
string address = 7;
}
//使用T开头测试
message TInt32{
int32 int1 = 1;
}
message TString{
string str1 = 1;
}
2.对数据进行解析
/*
如果proto结构体的变量是基础变量,比如int、string等等,那么set的时候直接调用set_xxx即可。
如果变量是自定义类型(也就是message嵌套),那么C++的生成代码中,就没有set_xxx函数名,取而代之的是三个函数名:
set_allocated_xxx()
release_xxx()
mutable_xxx()
使用set_allocated_xxx()来设置变量的时候,变量不能是普通栈内存数据,
必须是手动new出来的指针,至于何时delete,就不需要调用者关心了,
protobuf内部会自动delete掉通过set_allocated_设置的内存;
release_xxx()是用来取消之前由set_allocated_xxx设置的数据,
调用release_xxx以后,protobuf内部就不会自动去delete这个数据;
mutable_xxx()返回分配内存后的对象,如果已经分配过则直接返回,如果没有分配则在内部分配,建议使用mutable_xxx
*/
#if 1
message Person{
string name = 1;
int32 age = 2;
repeated string languages = 3;
Phone phone = 4;
repeated Book books = 5; // repeated 重复, 可以嵌套对象
bool vip = 6;
string address = 7;
}
#endif
bool ProtobufEncode(std::string &strPb)
{
IM::Login::Person person;
person.set_name("darren"); // 设置以set_为前缀
person.set_age(80);
person.add_languages("C++"); // 数组add
person.add_languages("Java");
// 电话号码
// mutable_ 嵌套对象时使用,并且是单个对象时使用,比如对应的Person里面的Phone phone = 4;
// 比如mutable_phone如果phone已经存在则直接返回,如果不存在则new 一个返回
IM::Login::Phone *phone = person.mutable_phone();
if(!phone)
{
std::cout << "mutable_phone failed." << std::endl;
return false;
}
phone->set_number("18570368134");
phone->set_phone_type(IM::BaseDefine::PHONE_HOME);
// 书籍
// add_则是针对repeated的嵌套对象,每次调用都返回一个新的对象,注意和mutable_的区别。
// 比如Person里面的repeated Book books = 5;
IM::Login::Book *book = person.add_books();
book->set_name("Linux kernel development");
book->set_price(7.7);
book = person.add_books();
book->set_name("Linux server development");
book->set_price(8.0);
// vip
person.set_vip(true);
// 地址
person.set_address("yageguoji");
uint32_t pbSize = person.ByteSize(); // 序列化后的大小
strPb.clear();
strPb.resize(pbSize);
uint8_t *szData = (uint8_t *)strPb.c_str();
if (!person.SerializeToArray(szData, pbSize)) // 拷贝序列化后的数据
{
std::cout << "person pb msg SerializeToArray failed." << std::endl;
return false;
}
return true;
}
3.解析数据
static void printPerson(IM::Login::Person &person)
{
std::cout << "name:\t" << person.name() << std::endl;
std::cout << "age:\t" << person.age() << std::endl;
std::string languages;
for (int i = 0; i < person.languages_size(); i++)
{
if (i != 0)
{
languages += ", ";
}
languages += person.languages(i);
}
std::cout << "languages:\t" << languages << std::endl;
if (person.has_phone()) // 自定义message的嵌套并且不是设置为repeated则有has_
{
// 注意引用
const IM::Login::Phone &phone = person.phone();
std::cout << "phone number:\t" << phone.number() << ", type:\t" << phone.phone_type() << std::endl;
}
else
{
std::cout << "no phone" << std::endl;
}
for (int i = 0; i < person.books_size(); i++)
{
const IM::Login::Book &book = person.books(i);
std::cout << "book name:\t" << book.name() << ", price:\t" << book.price() << std::endl;
}
std::cout << "vip:\t" << person.vip() << std::endl;
std::cout << "address:\t" << person.address() << std::endl;
}