protobuf使用
protobuf、json、xml
这三个都是一个序列化数据结构的格式,用于序列化和反序列化的一个数据载体。
作为序列化和反序列化的数据载体,程序使用这种数据格式一般的过程是
- A进程对某个特定数据机构进行数据填充
- 使用库函数基于特定数据结构进行序列化(protobuf、json、xml)
- A进程将序列化的数据发送给B进程
- B进程使用库函数将序列化数据反序列化提取到特定数据结构
这样整个过程下来,本质上,上面这三种数据结构就是能够可以将结构化的数据在进程间传输。
比较
序列化(反序列化)效率(时间消耗):protobuf > json > xml
序列化字节数:protobuf < json < xml
可读性:xml > json > protobuf
XML
文本数据格式,有效数据利用率较低;
本地配置、ui配置
protobuf
二进制数据格式;
业务内部使用,各个服务之间的rpc调用,即时通讯项目;
谷歌私有的协议,不属于国际标准。
proto文件编写语法
- repeated – 修饰为数组属性
- message – struct
模板代码
Welsey.Struct.proto
// 定义语法规则,通常proto3好于proto2,proto2好于proto1
// 默认是proto2
syntax="proto3";
// 定义作用域,下面定义的最后都会在该作用域下
package Welsey.Struct;
// 是否使用轻量化的库
// option optimize_for = LITE_RUNTIME;
enum PhoneType
{
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message Phone
{
PhoneType type = 1;
string number = 2;
}
message Person
{
// 后面的那个序号表示:在protobuf数据包序列化和反序列化时,对应字段的排序位置,一般直接按照顺序写1、2、3...即可
double value_double = 1; // double
float value_float = 2; // float
int32 value_int32 = 3; // int32 -- 使⽤变⻓编码,对于负值的效率很低,如果你的域有可能有负值,请使⽤sint64替代
uint32 value_uint32 = 4; // uint32 -- 使⽤变⻓编码
uint64 value_uint64 = 5; // uint64 -- 使⽤变⻓编码
sint32 value_sint32 = 6; // int32 -- 使⽤变⻓编码,这些编码在负值时比int32高效的多
sint64 value_sint64 = 7; // int64 -- 使⽤变⻓编码,有符号的整型值。编码时通常比int64高效
fixed32 value_fixed32 = 8; // uint32 -- 总是4个字节,如果数值总是⽐总是⽐2^28⼤的话,这个类型会⽐uint32⾼效。
fixed64 value_fixed64 = 9; // uint64 -- 总是8个字节,如果数值总是⽐总是⽐2^56⼤的话,这个类型会⽐uint64⾼效。
sfixed32 value_sfixed32 = 10; // int32 -- 总是4个字节
sfixed64 value_sfixed64 = 11; // int64 -- 总是8个字节
bool value_bool = 12; // bool
string value_string = 13; // string -- ⼀个字符串必须是UTF-8编码或者7-bit ASCII编码的⽂本。
bytes value_bytes = 14; // 可能包含任意顺序的字节数据
repeated Phone phone = 15; // repeated -- 数组
}
main.cpp
#include "Welsey.Struct.pb.h"
#include <string>
#include <iostream>
using namespace std;
bool ProtobufEncode(std::string &strPb)
{
Welsey::Struct::Person person;
person.set_value_double(1.1);
person.set_value_float(1.2);
person.set_value_int32(2);
person.set_value_uint32(3);
person.set_value_uint64(4);
person.set_value_sint32(5);
person.set_value_sint64(6);
person.set_value_fixed32(7);
person.set_value_fixed64(8);
person.set_value_sfixed32(9);
person.set_value_sfixed64(10);
person.set_value_bool(true);
person.set_value_string(string("welsey\01", 8));
person.set_value_bytes(string("welsey\02", 8));
Welsey::Struct::Phone *phone = person.add_phone();
phone->set_number("123456");
phone->set_type(Welsey::Struct::HOME);
phone = person.add_phone();
phone->set_number("654321");
phone->set_type(Welsey::Struct::MOBILE);
/**
* @brief 进行序列化
*/
size_t pbSize = person.ByteSizeLong(); // 获取序列化后的大小
strPb.clear();
strPb.resize(pbSize);
uint8_t *szData = (uint8_t *)strPb.c_str();
// 将person序列化后的数据存储在szData
if (!person.SerializeToArray(szData, pbSize)) // 拷贝序列化后的数据
{
std::cout << "person pb msg SerializeToArray failed." << std::endl;
return false;
}
return true;
}
static void printPerson(Welsey::Struct::Person &person)
{
std::cout << "double:\t" << person.value_double() << std::endl;
std::cout << "float:\t" << person.value_float() << std::endl;
std::cout << "int32:\t" << person.value_int32() << std::endl;
std::cout << "uint32:\t" << person.value_uint32() << std::endl;
std::cout << "uint64:\t" << person.value_uint64() << std::endl;
std::cout << "sint32:\t" << person.value_sint32() << std::endl;
std::cout << "sint64:\t" << person.value_sint64() << std::endl;
std::cout << "fixed32:\t" << person.value_fixed32() << std::endl;
std::cout << "fixed64:\t" << person.value_fixed64() << std::endl;
std::cout << "sfixed32:\t" << person.value_sfixed32() << std::endl;
std::cout << "sfixed64:\t" << person.value_sfixed64() << std::endl;
std::cout << "bool:\t" << person.value_bool() << std::endl;
std::cout << "string:\t" << person.value_string() <<"\t" << person.value_bytes().size() << std::endl;
std::cout << "bytes:\t" << person.value_bytes() <<"\t" << person.value_bytes().size() << std::endl;
for (int i = 0; i < person.phone_size(); i++)
{
const Welsey::Struct::Phone &phone = person.phone(i);
std::cout << "phone num:\t" << phone.number()<<"\t"<<phone.type()<< std::endl;
}
}
bool ProtobufDecode(std::string &strPb)
{
Welsey::Struct::Person person;
person.ParseFromArray(strPb.c_str(), strPb.size()); // 反序列化
printPerson(person);
return true;
}
int main(void)
{
std::string strPb;
ProtobufEncode(strPb); // 序列化后是二进制
ProtobufDecode(strPb);
return 0;
}
makefile
all : target
target : Welsey.Struct.proto main.cpp
protoc -I=./ --cpp_out=./ ./*.proto # --cpp_out 生成protobuf与cpp相关的文件
protoc -I=./ --java_out=./ ./*.proto # --java_out 生成protobuf与java相关的文件
protoc -I=./ --python_out=./ ./*.proto # --python_out 生成protobuf与python相关的文件
g++ -std=c++11 -o target main.cpp Welsey.Struct.pb.cc -lprotobuf -lpthread -L/usr/local/protobuf/lib