ProtoBuf3 C++使用篇
protobuf 是用于结构化数据串行化的灵活、高效、自动化的解决方案。又如 XML,不过它更小、更快、也更简单。你只需要按照你想要的数据存储格式编写一个.proto,然后使用生成器生成的代码来读写这个数据结构。更重要的是,你甚至可以在无需重新部署程序的情况下更新数据结构。
在项目中使用protocol buffers需要经历如下三步:
(1).定义消息格式文件,最好以proto作为后缀名
(2).使用Google提供的protocol buffers编译器来生成代码文件,一般为.h和.cc文件,主要是对消息格式以特定的语言方式描述
(3).使用protocol buffers库提供的API来编写应用程序
1.先来定义一个
本消息将以客户端请求登录和服务端返回为列
syntax = "proto3";
package pt;
option optimize_for = LITE_RUNTIME; message req_login
{
string username = ;
string password = ;
} message obj_user_info
{
string nickname = ; //昵称
string icon = ; //头像
int64 coin = ; //金币
string location = ; //所属地
} //游戏数据统计
message obj_user_game_record
{
string time = ;
int32 kill = ; //击杀数
int32 dead = ; //死亡数
int32 assist= ; //助攻数
} message rsp_login
{
enum RET {
SUCCESS = ;
ACCOUNT_NULL = ; //账号不存在
ACCOUNT_LOCK = ; //账号锁定
PASSWORD_ERROR = ; //密码错误
ERROR = ;
}
int32 ret = ;
obj_user_info user_info = ;
repeated obj_user_game_record record = ;
}
2.生成目标语言代码
下面的命令帮助我们将game.proto文件中定义的Protocol Buffer格式的消息编译成C++代码文件。
//SRC_DIR .proto文件存放目录
//--cpp_out 指示编译器生成C++代码,DST_DIR为生成文件存放目录
//game.proto 待编译的协议文件
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/game.proto
由于我们在game.proto文件中定义选项optimize_for=LITE_RUNTIME,因此由该文件内生成的所有C++类的父类均为::google::protobuf::MessageLite,而非::google::protobuf::Message。MessageLite类是Message的父类,MessageLite中缺少对反射的支持,而此类功能均在Message类中提供了具体的实现。
对于我们的项目而言,整个系统相对比较封闭,不会和外部程序进行交互,与此同时,我们的客户端部分又是运行在Android平台,有鉴于此,我们考虑使用LITE版本的Protocol Buffer。这样不仅可以得到更高编码效率,而且生成代码编译后所占用的资源也会更少,至于反射所能带来的灵活性和极易扩展性,对于该项目而言完全可以忽略。
3.protobuf自动生成的API
class rsp_login : public ::google::protobuf::MessageLite
{
public:
//每一个message类都包含以下方法供你检测或操作
void CopyFrom(const rsp_login& from);
void MergeFrom(const rsp_login& from);
void Clear(); //清除所有字段内容,并置为空状态
bool IsInitialized() const; //检测所有required 是否初始化
int ByteSize() const; //类所占字节数 //整形变量只提供获取、修改、清除
void clear_ret();
::google::protobuf::int32 ret() const;
void set_ret(::google::protobuf::int32 value); //自定义类类型user_info
bool has_user_info() const;
void clear_user_info();
const ::pt::obj_user_info& user_info() const;
//自定义类型,并没提供set方法,而是通过mutable_接口返回user_info的指针,可根据此指针进行赋值操作
::pt::obj_user_info* mutable_user_info();
//返回user_info字段指针,将所有权移交给此指针,并将user_info字段置为empty状态
::pt::obj_user_info* release_user_info();
//使用set_allocated要小心,传入的参数需要显示allocate,设置后函数内部维护此指针
void set_allocated_user_info(::pt::obj_user_info* user_info); //record为repeated的类数组类型
int record_size() const;
void clear_record();
//根据id索引,返回记录的引用,const不可修改内容
const ::pt::obj_user_game_record& record(int index) const;
//根据id索引,返回记录的指针,以供查看、修改
::pt::obj_user_game_record* mutable_record(int index);
//repeated类型提供add接口增加一条记录,并返回此记录的指针,以便对其赋值
::pt::obj_user_game_record* add_record();
//提供mutable接口,并返回record字段的容器指针,可根据此指针遍历、修改
::google::protobuf::RepeatedPtrField< ::pt::obj_user_game_record >* mutable_record();
//返回record字段的容器引用,const不可修改内容
const ::google::protobuf::RepeatedPtrField< ::pt::obj_user_game_record >& record() const;
}
4.protobuf读和写
#include <iostream>
#include <string>
#include "game.pb.h" int main()
{
pt::rsp_login rsp{};
rsp.set_ret(pt::rsp_login_RET_SUCCESS);
auto user_info = rsp.mutable_user_info();
user_info->set_nickname("dsw");
user_info->set_icon("345DS55GF34D774S");
user_info->set_coin();
user_info->set_location("zh"); for (int i = ; i < ; i++) {
auto record = rsp.add_record();
record->set_time("2017/4/13 12:22:11");
record->set_kill(i * );
record->set_dead(i * );
record->set_assist(i * );
} std::string buff{};
rsp.SerializeToString(&buff);
//------------------解析----------------------
pt::rsp_login rsp2{};
if (!rsp2.ParseFromString(buff)) {
std::cout << "parse error\n";
} auto temp_user_info = rsp2.user_info();
std::cout << "nickname:" << temp_user_info.nickname() << std::endl;
std::cout << "coin:" << temp_user_info.coin() << std::endl;
for (int m = ; m < rsp2.record_size(); m++) {
auto temp_record = rsp2.record(m);
std::cout << "time:" << temp_record.time() << " kill:" << temp_record.kill() << " dead:" << temp_record.dead() << " assist:" << temp_record.assist() << std::endl;
}
}
输出如下:
nickname:dsw
coin:
time:// :: kill: dead: assist:
time:// :: kill: dead: assist:
time:// :: kill: dead: assist:
time:// :: kill: dead: assist:
time:// :: kill: dead: assist:
4.扩展protoobuf
在你发布了使用Protocol-Buffers的代码之后, 你必定会想"改进"message的定义. 如果你想让你的新message向后兼容, 并且旧的message能够向前兼容。你一定希望如此,那么你在新的Person 中就要遵守其他的一些规则了:
(1).对已存在的任何字段, 你都不能更改其标识tag号。
(2).你绝对不能添加或删除任何required的字段。
(3).你可以添加新的optional或repeated的字段, 但是你必须使用新的标识tag号(此message中从未使用过的标识号,甚至连已经被删除过标识号也不行)。
(4).有一些例外情况, 但是它们很少使用。
如果你遵守这些规则, 老代码将能很好地解析新的消息, 并忽略掉任何新的字段. 对老代码来说, 已经被删除的optional字段将被赋予默认值. 已被删除的repeated字段将是空的. 新的代码也能够透明地读取旧的消息. 但是请牢记心中: 新的optional字段将不会出现在旧的消息中, 如果没有为一个optional项指定默认值, 那么就会使用与特定类型相关的默认值: 对string(null)、boolean(false)、数值类型(0)。
还要注意: 如果你添加了一个新的repeated字段, 你的新代码将无法告诉你它是否被留空了(被新代码), 或者是否从未被置值(被旧代码), 这是因为它没有has_标志.
ProtoBuf3 C++使用篇的更多相关文章
- TGL站长关于常见问题的回复
问题地址: http://www.thegrouplet.com/thread-112923-1-1.html 问题: 网站配有太多的模板是否影响网站加载速度 月光答复: wp不需要删除其他的模板,不 ...
- Netty4.x整合SpringBoot2.x使用Protobuf3详解
前言 本篇文章主要介绍的是SpringBoot整合Netty以及使用Protobuf进行数据传输的相关内容.Protobuf会介绍下用法,至于Netty在netty 之 telnet HelloWor ...
- 故障重现(内存篇2),JAVA内存不足导致频繁回收和swap引起的性能问题
背景起因: 记起以前的另一次也是关于内存的调优分享下 有个系统平时运行非常稳定运行(没经历过大并发考验),然而在一次活动后,人数并发一上来后,系统开始卡. 我按经验开始调优,在每个关键步骤的加入如 ...
- 论:开发者信仰之“天下IT是一家“(Java .NET篇)
比尔盖茨公认的IT界领军人物,打造了辉煌一时的PC时代. 2008年,史蒂夫鲍尔默接替了盖茨的工作,成为微软公司的总裁. 2013年他与微软做了最后的道别. 2013年以后,我才真正看到了微软的变化. ...
- [ 高并发]Java高并发编程系列第二篇--线程同步
高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...
- [高并发]Java高并发编程系列开山篇--线程实现
Java是最早开始有并发的语言之一,再过去传统多任务的模式下,人们发现很难解决一些更为复杂的问题,这个时候我们就有了并发. 引用 多线程比多任务更加有挑战.多线程是在同一个程序内部并行执行,因此会对相 ...
- 操作系统篇-调用门与特权级(CPL、DPL和RPL)
|| 版权声明:本文为博主原创文章,未经博主允许不得转载. 一.前言 在前两篇文章(<操作系统篇-浅谈实模式与保护模式>和<操作系统篇-分段机制与GDT|LDT>)中,我们提到 ...
- 通过AngularJS实现前端与后台的数据对接(二)——服务(service,$http)篇
什么是服务? 服务提供了一种能在应用的整个生命周期内保持数据的方法,它能够在控制器之间进行通信,并且能保证数据的一致性. 服务是一个单例对象,在每个应用中只会被实例化一次(被$injector实例化) ...
- javascript动画系列第三篇——碰撞检测
前面的话 前面分别介绍了拖拽模拟和磁性吸附,当可视区域内存在多个可拖拽元素,就出现碰撞检测的问题,这也是javascript动画的一个经典问题.本篇将详细介绍碰撞检测 原理介绍 碰撞检测的方法有很多, ...
随机推荐
- PSD的单位及计算方法[转]
功率谱密度(PSD)的国际单位 功率谱密度(PSD),单位为:unit^2/Hz代表单位频率上信号的能量,所以是密度谱,幅值代表频段内的有效值平方. 如果是加速度功率谱密度,加速度的单位是m/s^ ...
- WPFToolkit DataGrid 使用介绍zz
首先:这版本需要.NetFrameWork SP1的支持 WPF Toolkit - February 2010 Release 下载地址:http://wpf.codeplex.com/rele ...
- 如何解决Failed to retrieve MSVC Environment from XXXXXXXX
升级了新版的Qt5.9.3后,本人的电脑也出了这个问题. 最后通过删除了path中的一些错误.多余的环境变量解决了.(删除了一些mysql的环境变量)
- 游历校园 [COGS 614] [欧拉图]
Description 刷完牙洗完脸,黄黄同学就要上课去了.可是黄黄同学每次去上课时总喜欢把校园里面的每条路都走一遍,当然,黄黄同学想每条路也只走一遍.我们一般人很可能对一些地图是办不到每条路走一遍且 ...
- 2017.07.14【NOIP提高组】模拟赛B组
Summary 这次比赛因为迟到了,少了很多时间,也受到了相应的惩罚,这是好的,是个标记牌,警醒着我.这次比赛的题目很难,也就是说,大家的得分都很低,总的来说,收获还是很大的,因为有非常多的技巧被掌握 ...
- 编程菜鸟的日记-初学尝试编程-C++ Primer Plus 第4章编程练习2
#include <iostream>#include <string>int main(){ using namespace std; string name; string ...
- hiredis 使用 linux c++
1.linux下如何安装hiredis 1)下载地址 https://github.com/redis/hiredis 2)编译和安装 解压后的文件夹执行 make;make install; 3) ...
- Miller Rabin素数检测
#include<iostream> #include<cstdio> #include<queue> #include<cstring> #inclu ...
- IT职业后半段发展问题
忆: 八年前,当我结束第二份工作,寻求第三份工作的时候,我就有了一个疑惑,IT职场上45岁以上或是50岁以上的人去哪了,我去请教以前的老领导,他告诉我有一些转行了,有一些他也不清楚,我的老领导也就比我 ...
- ARM 技术文档
1. 相关链接 ARM官网: http://infocenter.arm.com/ 比较有用的几个目录: ARM Technical Support Knowledge Articles 一些关于A ...