目录
一、Protobuf序列化概述
protobuf是一种比json和xml等序列化工具更加轻量和高效的结构化数据存储格式,性能比json和xml真的强很多,毕竟google出品。
官网:https://developers.google.com/protocol-buffers/https://developers.google.com/protocol-buffers/
二、Protobuf的原理
三、protobuf 的安装
apt-get install autoconf automake libtool curl make g++ unzip
$ git clone https://github.com/protocolbuffers/protobuf.git
$ cd protobuf
$ git submodule update --init --recursive
$ ./autogen.sh
$ ./configure
$ make
$ make check
$ sudo make install
$ sudo ldconfig
四、定义message
所有的message必须定义到一个文件中,且文件的后缀名为.proto。例如我们定义的bike.proto文件
syntax = "proto2";
package tutorial;
message mobile_request
{
required string mobile = 1;
}
message mobile_response
{
required int32 code = 1; //响应代号
required int32 icode = 2; //验证码
optional string data = 3; //失败原因
}
message login_request
{
required string mobile = 1; // 手机号码
required int32 icode = 2; // 验证码
}
message login_response
{
required int32 code = 1; // 响应代号
optional string desc = 2; // 验证码
}
message recharge_request
{
required string mobile = 1; // 手机号码
required int32 amount = 2; // 充值金额
}
message recharge_response
{
required int32 code = 1; // 响应代号
optional string desc = 2; // 验证码
required int32 balance = 3; // 最新的余额
}
message account_balance_request
{
required string mobile = 1;
}
message account_balance_response
{
required int32 code = 1; // 响应代号
optional string desc = 2; // 验证码
required int32 balance = 3;
}
message list_account_records_request
{
required string mobile = 1;
}
message list_account_records_response
{
required int32 code = 1; // 响应代号
optional string desc = 2; // 验证码
message account_record
{
required int32 type = 1; // 0 : 骑行消费, 1 : 充值, 2 : 退款
required int32 limit = 2; // 消费或者充值金额
required uint64 timestamp = 3; // 记录发生时的时间戳
}
repeated account_record records = 3;
}
message list_travel_records_request
{
required string mobile = 1;
}
message list_travel_records_response
{
required int32 code = 1; // 响应代号
optional string desc = 2; // 验证码
message travel_record
{
required uint64 stm = 1; // start timestamp
required uint32 duration = 2; // 骑行时长
required uint32 amount = 3; // 所耗金额
}
required double mileage = 3; // 里程
required double discharge = 4; // 排放
required double calorie = 5; // 卡路里
repeated travel_record records = 6;
}
五、编译message文件
编译语法:
protoc -I=$SRC_DIR --cpp_out=$DST_DIR bike.proto
SRC_DIR 表示proto文件所在的目录,cpp_out指定了生成的代码的路径, bike.proto指proto文件名。
protoc -I=./ --cpp_out=./ bike.proto
这样在当前目录生成了bike.pb.cc和bike.pb.h两个文件。
编译生成的c++文件
g++ -std=c++11 example.cc bike.pb.cc -lprotobuf
六、应用Protobuf
把生成了protocol.pb.cc和protocol.pb.h加入到工程,那么接着就是调用一些API,完成序列化和反序列化。
API说明 : https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.messagehttps://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.message
七、Message的使用
1、Message的基本用法
范例1: example1.cc
#include "bike.pb.h"
#include <string>
#include <iostream>
using namespace std;
using namespace tutorial;
int main(void)
{
std::string data; //存储序列化的消息
//客户端发送请求
{
mobile_request mr;
mr.set_mobile("18684518289");
mr.SerializeToString(&data);
cout<<"序列化后的数据["<<data.length()<<"]: "<< data << endl;
cout<<hex<<(int)*((char*)data.c_str())<<endl;
cout<<hex<<(int)*((char*)data.c_str() + 1)<<endl;
//客户端发送data send(sockfd, data.c_str(), data.length());
}
//服务器端接受请求
{
//receive(sockfd, data, ...);
mobile_request mr;
mr.ParseFromString(data);
cout<<"客户端手机号码: " << mr.mobile() << endl;
}
return 0;
}
2、Message的嵌套使用
范例2: example1.cc
#include "bike.pb.h"
#include <string>
#include <iostream>
using namespace std;
using namespace tutorial;
int main(void)
{
std::string data; //存储序列化的消息
//客户端发送请求
{
list_account_records_response larr;
larr.set_code(200);
larr.set_desc("ok");
for(int i=0; i<5; i++)
{
list_account_records_response_account_record * ar = larr.add_records();
ar->set_type(0);
ar->set_limit(i * 100);
ar->set_timestamp(time(NULL));
}
printf("recoreds size : %d\n", larr.records_size());
larr.SerializeToString(&data);
//客户端发送data send(sockfd, data.c_str(), data.length());
}
//服务器端接受请求
{
list_account_records_response larr;
larr.ParseFromString(data);
printf("recoreds size : %d\n", larr.records_size());
printf("code: %d\n", larr.code());
for(int i=0; i<larr.records_size(); i++)
{
const list_account_records_response_account_record &ar = larr.records(i);
printf("limit: %d\n", ar.limit());
}
//cout<<"客户端手机号码: " << mr.mobile() << endl;
}
return 0;
}