protobuf c/c++使用
简介
Protobuf全称是Google Protocol Buffer,是一种高效轻便的结构化数据存储方式,可用于(数据)通信协议、数据存储等。
也可以理解为结构化数据的序列化方法。
protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。
Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。
你可以定义数据的结构,然后使用特殊生成的源代码轻松的在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。
使用
第一步:创建.proto文件,定义数据结构,如下:
//Filename:dev_func.proto
syntax="proto3";
import "google/protobuf/any.proto";
//import "common.proto";
package dev_func;
message DEV_FUNC_REQ{
uint64 msgSeq = 1;
string devId = 2;
repeated FuncReq funcReq = 3;
repeated google.protobuf.Any extensions = 4;
}
message FuncReq{
oneof oneofFuncType{
VehFuncType vehFuncType = 2;
RsuFuncType recFuncType = 3;
RecFuncType rsuFuncType = 4;
}
uint32 funcVersion = 5;
bool switch = 6;//0:关,1:开
}
enum VehFuncType{
VEH_FUNC_UNKNOWN = 0;
VEH_FUNC_RESERVED1 = 1;
VEH_FUNC_RESERVED2 = 2;
VEH_FUNC_RESERVED3 = 3;
}
enum RsuFuncType{
RSU_FUNC_UNKNOWN = 0;
RSU_FUNC_RESERVED1 = 3;
RSU_FUNC_RESERVED2 = 4;
RSU_FUNC_RESERVED3 = 5;
RSU_FUNC_RESERVED4 = 6;
}
enum RecFuncType{
REC_FUNC_UNKNOWN = 0;
REC_FUNC_RESERVED1 = 3;
REC_FUNC_RESERVED2 = 4;
REC_FUNC_RESERVED3 = 5;
}
上述图片中,我们定义了DEV_FUNC_REQ的数据结构,标识符为message或enum,如示例中的DEV_FUNC_REQ和FuncReq。message标识一条消息,enum标识一个枚举类型。使用protobuf编译器将协议文件编译后,message和enum都会生成一个类。
当我们某一个字段可能出现多种不同类型,那么就可以使用oneof。
syntax="proto3"协议版本
message XXX{
// 字段规则:required -> 字段只能也必须出现 1 次
// 字段规则:optional -> 字段可出现 0 次或1次
// 字段规则:repeated -> 字段可出现任意多次(包括 0)
// 类型:int32、int64、sint32、sint64、string、32-bit ....
// 字段编号:0 ~ 536870911(除去 19000 到 19999 之间的数字)
字段规则 类型 名称 = 字段编号;
}
第二步:使用proto编译工具编译.proto文件
在linux环境下安装protoc工具
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/xxx.proto
-I 文件生成路径
–cpp_out :生成c++文件(proto3不支持生成c类型)可支持多种语言类型
使用proto编译工具根据.proto文件生成对应语言的源文件如下生成.cc与.h文件
第三步:调用接口,实现序列化与反序列化
函数接口中开始添加宏GOOGLE_PROTOBUF_VERIFY_VERSION
static int cpcc_encode_dev_func_req(unsigned char *body_buff,unsigned char msgtype)
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
int uindex = 0;
unsigned char bufflen[4] = {0};
序列化
DEV_FUNC_REQ dev_func_req;
dev_func_req.set_msgseq(dev_func_msg_seq++);
dev_func_req.set_devid(1);
FuncReq *funcReq = dev_func_req.add_funcreq();
veh_data = tb_nv_getint("cpcc_veh_func_type");
funcReq->set_vehfunctype((VehFuncType)veh_data);
funcReq->set_funcversion(fun_seq++);
veh_data = tb_nv_getint("cpcc_veh_func_type_switch");
funcReq->set_switch_((bool)veh_data);
CPCC_LOG_DEBUG("VEH TYPE IS %d\n",funcReq->oneofFuncType_case());
string serial_buf;
dev_func_req.SerializeToString(&serial_buf);
反序列化
DEV_FUNC_RES dev_func_res;
dev_func_res.ParseFromArray(read_ptr+uindex,payloadlen);
CPCC_LOG_DEBUG("recv fun rsp msg,funcres_size is %d\n",dev_func_res.funcres_size());
for(int i = 0 ; i < dev_func_res.funcres_size() ; i++)
{
FuncRes funcRes = dev_func_res.funcres(i);
CPCC_LOG_DEBUG("func res type is %d\n",funcRes.oneofFuncType_case());
if(funcRes.oneofFuncType_case() == VEH_FUNC_CPCC)
{
if(funcRes.resflag())
{
CPCC_LOG_DEBUG("fun req is success\n");
}
else
{
CPCC_LOG_ERROR("fun req is failed and fail reason is %d\n",funcRes.failreason());
}
}
}
详细protobuf相关内容及API接口参考路径:
https://developers.google.cn/protocol-buffers/docs/cpptutorial