protobuf实践+生成C++代码的解析

目录

1.实践1(简单使用)

2.实践2(存储列表类数据)

3.实践3(定义RPC方法)

4.解析protobuf的message类

5.解析protobuf的service类

6.Rpcchannel是什么呢?


1.实践1(简单使用)

下图是我的项目代码工程。我们在test创建protobuf文件夹。然后在protobuf文件下创建main.cc和test.proto进行我们的实践。

我们先在test.proto定义消息类型(message)
注意:里面的类型都是谷歌protobuf定义的类型,和C++的类型相似
我们用bytes定义字符串类型,多字节存储,处理的是字节,省时省消耗
如果写成string,还要进行多字节的转码,把字符转成字节存储。
因为protobuf的二进制存储的

syntax = "proto3";//声明了protobuf的版本package fixbug;//声明了代码所在的包(对于C++来说是namespace)//定义登录请求消息类型   name   pwd
message LoginRequest
{string name = 1;string pwd = 2;
}//定义登录响应消息类型
message LoginResponse
{int32 errcode = 1;string errmsg = 2;bool success = 3;
}

优化后代码: 

syntax = "proto3";//声明了protobuf的版本package fixbug;//声明了代码所在的包(对于C++来说是namespace)message ResultCode//封装一下失败类,减少代码重复量
{int32 errcode = 1;//错误码bytes errmsg = 2;//错误消息
}
//数据(单个数据) 列表(数组) 映射表(map)
//定义登录请求消息类型   name   pwd
message LoginRequest
{bytes name = 1;bytes pwd = 2;
}//定义登录响应消息类型
message LoginResponse
{ResultCode result=1;bool success = 2;
}

我们配置完test.proto之后,打开终端,进入到protobuf中
输入命令:protoc test.proto --cpp.out=./
生成了teat.pb.cc和test.pb.h两个文件,在当前目录

温馨提示:我们写完文件退出保存后再去编译运行它!
可以看到我们之前定义的LoginRequest是一个class类!
我们定义的name,pwd相当于就是LoginRequest类的成员变量,也有相应的成员方法!

 接下来我们打开main.cc,编码测试protobuf!

#include "test.pb.h"
#include <iostream>
#include <string>
using namespace fixbug;int main()
{//封装了login请求对象的数据LoginRequest reg;reg.set_name("zhang san");reg.set_pwd("123456");//对象数据序列化 =》char*std::string send_str;if(reg.SerializeToString(&send_str)){std::cout<<send_str.c_str()<<std::endl;}//从send_str反序列化一个login请求对象LoginRequest reqB;if(reqB.ParseFromString(send_str)){std::cout<<reqB.name()<<std::endl;std::cout<<reqB.pwd()<<std::endl;}return 0;
}

我们保存文件,打开终端,输入以下命令

因为我们的protobuf是生成动态库,所以要加上-lprotobuf
生成a.out文件

序列化成
zhang san123456
反序列化成
zhang san
123456

2.实践2(存储列表类数据)

我们在存储数据的时候,有3种形式:
数据(单个数据) 列表(数组) 映射表(map)

以获取好友列表为例,我们先在test.proto定义消息类型

syntax = "proto3";//声明了protobuf的版本package fixbug;//声明了代码所在的包(对于C++来说是namespace)message ResultCode//封装一下失败类,减少代码重复量
{int32 errcode = 1;//错误码bytes errmsg = 2;//错误消息
}
//数据(单个数据) 列表(数组) 映射表(map)
//定义登录请求消息类型   name   pwd
message LoginRequest
{bytes name = 1;bytes pwd = 2;
}//定义登录响应消息类型
message LoginResponse
{ResultCode result=1;bool success = 2;
}//定义获取好友列表的请求
message GetFriendListsRequest
{uint32 userid=1;
}message User
{bytes name=1;uint32 age=2;enum Sex{MAN=0;WOMAN=1;}Sex sex=3;
}
//定义获取好友列表的消息响应
message GetFriendListsResponse
{ResultCode result = 1;repeated User friend_list = 2;//定义了一个列表类型(列表存储,存储多个好友信息)}

保存,打开终端进入到protobuf,输入命令
protoc test.proto --cpp_out=./

接下来我们打开main.cc

#include "test.pb.h"
#include <iostream>
#include <string>
using namespace fixbug;int main()
{// LoginResponse rsp;// ResultCode *rc=rsp.mutable_result();//获取指针// rc->set_errcode(1);// rc->set_errmsg("登录处理失败了");GetFriendListsResponse rsp;ResultCode *rc=rsp.mutable_result();rc->set_errcode(0);User *user1=rsp.add_friend_list();user1->set_name("zhang san");user1->set_age(20);user1->set_sex(User::MAN);std::cout<<rsp.friend_list_size()<<std::endl;return 0;
}

输出的是好友的数量。

3.实践3(定义RPC方法)

在protobuf里面怎么定义描述rpc方法的类型?
传输RPC方法名字和所调用方法的参数

protobuf本身没有提供rpc通信功能。
我们是要它做RPC方法调用的序列化和反序列化!
在test.proto配置如下

rpc Login相当于是定义一个login的rpc方法,login是rpc方法的名字,protobuf不支持rpc通信功能,只支持对于rpc方法的描述,通过这个描述,它就可以去做rpc请求的携带的参数的序列化和反序列化,login的小括号就存储实参的protobuf的类型表示,returns就是表示:这个rpc方法login()执行以后返回的protobuf打包的类型。

test.proto全套代码:
message描述的都是class类,定义option,表示生成service服务类和rpc方法描述,否则默认不生成。

syntax = "proto3";//声明了protobuf的版本package fixbug;//声明了代码所在的包(对于C++来说是namespace)//定义下面的选项,表示生成service服务类和rpc方法描述,默认不生成
option cc_generic_services=true;message ResultCode//封装一下失败类,减少代码重复量
{int32 errcode = 1;//错误码bytes errmsg = 2;//错误消息
}
//数据(单个数据) 列表(数组) 映射表(map)
//定义登录请求消息类型   name   pwd
message LoginRequest
{bytes name = 1;bytes pwd = 2;//map<int32,string> test = 3;
}//定义登录响应消息类型
message LoginResponse
{ResultCode result=1;bool success = 2;
}//定义获取好友列表的请求
message GetFriendListsRequest
{uint32 userid=1;
}message User
{bytes name=1;uint32 age=2;enum Sex{MAN=0;WOMAN=1;}Sex sex=3;
}
//定义获取好友列表的消息响应
message GetFriendListsResponse
{ResultCode result = 1;repeated User friend_list = 2;//定义了一个列表类型(列表存储,存储多个好友信息)
}//在protobuf里面怎么定义描述rpc方法的类型  - service
service UserServiceRpc
{rpc Login(LoginRequest) returns(LoginResponse);rpc GetFriendLists(GetFriendListsRequest) returns(GetFriendListsResponse);
}

保存,编译
 我们进入生成的test.pb.h看到,服务service生成了UserServiceRpc类和UserServiceRpc_stub类(桩,代理类)

相当于是说,本地调用一个RPC方法的时候,底层要做很多事情,这些事情都是由代理类来做的。

4.解析protobuf的message类

基类Message提供了很多成员方法!!!

5.解析protobuf的service类

我们先来看看生成的UserServiceRpc类有什么东西? 

是无参数的构造函数:
UserServiceRpc类是使用在rpc服务的提供者(callee,远程方法的执行端)

虚函数,让派生类重写。我们看到,这些生成方法的名字就是我们定义rpc服务的方法的名字。参数是基于回调的操作。
而且参数都是4个。而且是固定的。

我们得知道rpc方法的名字(属于哪一个类类型的方法)和调用函数方法的参数,都在ServiceDescriptor描述(服务的名字,服务里面的方法名字,参数,请求的是纯对象的oop方法)。

我们接着看,生成一个对应的stub,代理类。

这个类Stub是用在RPC调用的发起端(caller端,rpc服务的消费者)。

我们发现,stub类是没有默认构造函数的,有带参数的构造函数,需要传Rpcchannel指针。
Rpcchannel是什么? 
我们还注意到有一个成员变量

他也有这两个方法:

实际上是虚函数,因为都是从基类继承而来的,基类的方法是虚函数

区别:
UserService有默认的构造函数,构造的时候不用传参数
UserService_Stub没有默认的构造函数,要传Rpcchannel指针,而且有一个成员变量:Rpcchannel指针,接收了构造函数的实参

我们发现:不管是调用什么方法,底层都是调用channel的CallMethod方法!
method(0)和method1(1)肯定是区分方法的名字

6.Rpcchannel是什么呢?

是一个抽象类

意味着我们必须自己去实现一个类,从Rpcchannel继承而来,重写CallMethod方法。

就是传自己实现的MyRpcChannel给Rpcchannel指针,派生类是可以用基类指针的。
到时候,调用stub的login方法或者getfriendlist方法都是基类指针指向了派生类同名的方法。

用stub桩类不管调用哪个方法,最终都调用到我们的MyRpcChannel的CallMethod方法,我们在这里(xxxxx部分)就可以进行rpc方法的序列化和反序列化,然后发起远程的rpc调用请求。

message类是专门用作rpc方法的参数和返回值的序列化和反序列化的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/34317.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Django中,update_or_create()

在Django中&#xff0c;可以使用update_or_create()方法来更新现有记录或创建新记录。该方法接受一个字典作为参数&#xff0c;用于指定要更新或创建的字段和对应的值。 update_or_create()方法的语法如下&#xff1a; 代码语言&#xff1a;python obj, created Model.obje…

python遍历文件夹中所有图片

python遍历文件夹中的图片-CSDN博客 这个是之前的版本&#xff0c;现在这个版本会更好&#xff0c;直接进来就在列表中 path glob.glob("1/*.jpg")print(path)print(len(path))path_img glob.glob("1/*.jpg")path_img.extend(path)print(len(path_img))…

问题解决:数据库自增id到最大报错

pgsql数据库id自增到长度问题&#xff1a; django.db.utils.DataError: nextval: reached maximum value of sequence "ip_prefix_info_id_seq" (32767) schema_name: ip_management_app table_name: ip_prefix_info # 先把自增id改到serial8&#xff0c;范围改大#…

行列视(RCV)在系统管理中的应用:解决生产型企业数据治理的挑战

行列视&#xff08;RCV&#xff09;作为一款面向生产型企业的综合性数据应用系统&#xff0c;在系统管理中扮演着至关重要的角色&#xff0c;特别是在解决生产型企业数据治理的挑战方面&#xff0c;表现出了卓越的性能。 首先&#xff0c;生产型企业面临着复杂而繁琐的数据治理…

学期结束如何发布期末成绩?

当期末的试卷最后一张被收起&#xff0c;当教室里的喧嚣逐渐沉寂&#xff0c;学生们的心中充满了对成绩的期待与忐忑。期末成绩&#xff0c;关乎着学生的心情&#xff0c;更关系到他们的未来学习动力。那么&#xff0c;如何在保护学生隐私的同时&#xff0c;高效地公布成绩呢&a…

vscode cmake debug 调试

在 VSCode 中调试使用 CMake 编译的程序&#xff0c;按照以下步骤进行&#xff1a; 1. **安装必要的扩展&#xff1a;** - 打开 VSCode&#xff0c;并确保你已经安装了以下扩展&#xff1a; - C/C&#xff08;由 Microsoft 提供&#xff09; - CMake - CMak…

Python Sqlalchemy基础使用

Python Sqlalchemy基础使用 Python Sqlalchemy基础使用基本使用创建Session创建ORM对象查询插入 进阶操作插入存在时更新执行SQL Python Sqlalchemy基础使用 这里记录一下&#xff0c;在编写python代码过程中使用Sqlalchemy的封装和基本使用方法。 (持续完善ing) 基本使用 …

代码随想录算法训练营Day48|188.买卖股票的最佳时机IV、309.最佳买卖股票时间含冷冻期、714.买卖股票的最佳时机含手续费

买卖股票的最佳时机IV . - 力扣&#xff08;LeetCode&#xff09; 至多可以购买k次&#xff0c;相比买卖股票的最佳时机III至多购买2次&#xff0c;区别在于次数不确定。 每买卖一次&#xff0c;dp数组的第二维度加2&#xff0c;dp数组的第二维度为2k1&#xff08;0-2k&…

TDengine 3.2.3.0 集成英特尔 AVX512!快来看看为你增添了哪些助力

在当今的 IoT 和智能制造领域&#xff0c;海量时序数据持续产生&#xff0c;对于这些数据的实时存储、高效查询和分析已经成为时序数据库&#xff08;Time Series Database&#xff0c;TSDB&#xff09;的核心竞争力。作为一款高性能的时序数据库&#xff0c;TDengine 不仅采用…

Pandas数据分析:掌握agg()方法的高级应用“

今天一个知识点&#xff1a; agg() 方法的 func 参数可以传入单个函数或函数列表。 agg() 方法在Pandas库中用于对DataFrame或Series的列进行聚合操作。func 参数可以传入单个&#xff08;值得注意的是&#xff0c;这里数据是一个单个而不是多个的内容&#xff0c;自己在这个…

【全开源】沃德会务会议管理系统(FastAdmin+ThinkPHP+Uniapp)

沃德会务会议管理系统一款基于FastAdminThinkPHPUniapp开发的会议管理系统&#xff0c;对会议流程、开支、数量、标准、供应商提供一种标准化的管理方法。以达到量化成本节约&#xff0c;风险缓解和服务质量提升的目的。适用于大型论坛、峰会、学术会议、政府大会、合作伙伴大会…

docker 安装达梦8

背景 X86-64架构使用Docker安装dm8_20240422_x86_rh6_64_rq_std_8.1.3.100_pack2.tar 1.下载Docker安装包 达梦官网下载dm8_20240422_x86_rh6_64_rq_std_8.1.3.100_pack2.tar安装包 快速下载通道&#xff1a; 达梦镜像包 2.将安装包上传至服务器&#xff0c;并加载镜像 拷…

结合人工智能的在线教育系统:开发与实践

人工智能&#xff08;AI&#xff09;正在革新各行各业&#xff0c;教育领域也不例外。结合AI技术的在线教育系统能够提供个性化的学习体验、智能化的教学辅助和高效的数据分析&#xff0c;从而大大提升教育质量和学习效果。本文将探讨结合AI技术的在线教育系统的开发与实践&…

如何调整C#中数组的大小

前言 数组存储多个相同类型的一种非常常用的数据结构。它长度是固定&#xff0c;也就是数组一旦创建大小就固定了。C# 数组不支持动态长度。那在C#中是否有方法可以调整数组大小呢&#xff1f;本文将通过示例介绍一种调整一维数组大小的方法。 方法 数组实例是从 System.Arr…

Type.GetTypeFromProgID 调用com组件

Type.GetTypeFromProgID 方法用于通过程序标识符&#xff08;ProgID&#xff09;获取 COM 类型。ProgID 是一个字符串标识符&#xff0c;用于标识 COM 组件。它通常在注册表中配置&#xff0c;并指向一个具体的 COM 类的 CLSID&#xff08;类标识符&#xff09;。 什么是 Prog…

【数据结构与算法】顺序查找、折半查找、分块查找

文章目录 顺序查找实现对有序表的顺序查找 二分查找&#xff08;折半查找&#xff09;实现二分查找判定树 分块查找&#xff08;索引顺序查找&#xff09;最理想的分块情况 顺序查找 顺序查找&#xff0c;又叫线性查找。适用于线性表。它的核心思路是从线性表的一端开始&#…

Unity的ScrollView滚动视图复用

发现问题 在游戏开发中有一个常见的需求&#xff0c;就是需要在屏幕显示多个&#xff08;多达上百&#xff09;显示item&#xff0c;然后用户用手指滚动视图可以选择需要查看的item。 现在的情况是在100个data的时候&#xff0c;Unity引擎是直接创建出对应的100个显示item。 …

13个行业数据分析指标体系如何建设100问

提供针对13个行业的数据分析指标体系的全面指南&#xff0c;涵盖各行业的关键指标和分析维度&#xff0c;帮助读者深入了解和构建有效的指标体系。以下是文章的主要内容&#xff1a; 电商行业数据指标体系&#xff1a;包括客户价值、商品、网站流量、整体运营、市场营销活动、市…

若依-前后端分离项目学习

第一天&#xff08;6.24&#xff09; 具体参考视频 b站 楠哥教你学Java 【【开源项目学习】若依前后端分离版&#xff0c;通俗易懂&#xff0c;快速上手】 https://www.bilibili.com/video/BV1HT4y1d7oA/?share_sourcecopy_web&vd_sourcecd9334b72b49da3614a4257…

C++如何实现继承和多态

继承 继承是指一个类&#xff08;子类&#xff09;从另一个类&#xff08;父类&#xff09;继承属性和方法。C支持单继承和多继承。 #include <iostream>// 基类&#xff08;父类&#xff09; class Animal { public:// 基类中的方法void eat() {std::cout << &q…