protobuf入门实践2
如何在proto中定义一个rpc服务?
syntax = "proto3"; //声明protobuf的版本package fixbug; //声明了代码所在的包 (对于C++来说就是namespace)//下面的选项,表示生成service服务类和rpc方法描述, 默认是不生成的
option cc_generic_services = true;message ResultCode{ //定义返回的错误码int32 errcode = 1;bytes errmsg = 2;
}//常用的数据类型: 数据、列表、映射表//定义登录请求消息类型 name pwd
message LoginRequest{bytes name = 1; //等于1表示这是第一个参数,一般string的存储定义为bytesbytes pwd = 2;// map<int32,string> test = 3; //映射表类型
}//定义登录响应消息类型
message LoginResponse{ResultCode result = 1;bool success = 3;
}message GetFriendsListRequest{uint32 user_id = 1;
}message User{bytes name = 1;uint32 age = 2;enum Sex{MAN = 0;WOMAN = 1;}Sex sex = 3;
}message GetFriendsListResponse{ResultCode result = 1;repeated User friend_list = 2; //定义了一个列表数据类型
}//在protobuf里面怎么定义描述rpc方法的类型---service
service UserService{rpc Login(LoginRequest) returns(LoginResponse);rpc GetFriendsList(GetFriendsListRequest) returns(GetFriendsListResponse);
}
关键字service用于定义rpc服务,例如Userservice有两个rpc服务,分别是Login和GetFriendsList, 返回值分别就是上述定义的消息类型。
老样子,先执行protoc xxx.proto --cpp_out=./ 生成对应的xxx.pb.cc 和 xxx.pb.h文件。
需要注意的是选项option cc_generic_services = true;得加上,默认是不生成的。
这边来分析xxx.pb.h文件,简单探究一下rpc调用过程:
//!!!!xxx.pb.h
class UserService : public ::PROTOBUF_NAMESPACE_ID::Service {protected:// This class should be treated as an abstract interface.inline UserService() {};public:virtual ~UserService();typedef UserService_Stub Stub;static const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor* descriptor();virtual void Login(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::LoginRequest* request,::fixbug::LoginResponse* response,::google::protobuf::Closure* done);virtual void GetFriendsList(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::GetFriendsListRequest* request,::fixbug::GetFriendsListResponse* response,::google::protobuf::Closure* done);// implements Service ----------------------------------------------const ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor* GetDescriptor();void CallMethod(const ::PROTOBUF_NAMESPACE_ID::MethodDescriptor* method,::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::PROTOBUF_NAMESPACE_ID::Message* request,::PROTOBUF_NAMESPACE_ID::Message* response,::google::protobuf::Closure* done);const ::PROTOBUF_NAMESPACE_ID::Message& GetRequestPrototype(const ::PROTOBUF_NAMESPACE_ID::MethodDescriptor* method) const;const ::PROTOBUF_NAMESPACE_ID::Message& GetResponsePrototype(const ::PROTOBUF_NAMESPACE_ID::MethodDescriptor* method) const;private:GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UserService);
};
//!!!!xxx.pb.cc
void UserService::Login(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::LoginRequest*,::fixbug::LoginResponse*,::google::protobuf::Closure* done) {controller->SetFailed("Method Login() not implemented.");done->Run();
}void UserService::GetFriendsList(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::GetFriendsListRequest*,::fixbug::GetFriendsListResponse*,::google::protobuf::Closure* done) {controller->SetFailed("Method GetFriendsList() not implemented.");done->Run();
}
可以看到一个UserService这个类,这个和message关键字有异曲同工之妙,都是对应的一个类,只不过继承的基类是有所不同的, message消息类型继承于抽象类message, service服务类型继承于抽象类service。此外可以发现在类中实现了在proto文件中定义的两个rpc方法Login和GetFriendsList, 其中两个参数是很熟悉的,request和response,也即这个rpc方法的需要用到的调用参数,类型message基类指针,表示可以接受任意消息类型。
由此可知UserService类是一个服务提供者(Callee)
再来看另一个类
//!!!!xxx.pb.h
class UserService_Stub : public UserService {public:UserService_Stub(::PROTOBUF_NAMESPACE_ID::RpcChannel* channel);UserService_Stub(::PROTOBUF_NAMESPACE_ID::RpcChannel* channel,::PROTOBUF_NAMESPACE_ID::Service::ChannelOwnership ownership);~UserService_Stub();inline ::PROTOBUF_NAMESPACE_ID::RpcChannel* channel() { return channel_; }// implements UserService ------------------------------------------void Login(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::LoginRequest* request,::fixbug::LoginResponse* response,::google::protobuf::Closure* done);void GetFriendsList(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::GetFriendsListRequest* request,::fixbug::GetFriendsListResponse* response,::google::protobuf::Closure* done);private:::PROTOBUF_NAMESPACE_ID::RpcChannel* channel_;bool owns_channel_;GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UserService_Stub);//!!!!xxx.pb.cc
void UserService_Stub::Login(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::LoginRequest* request,::fixbug::LoginResponse* response,::google::protobuf::Closure* done) {channel_->CallMethod(descriptor()->method(0),controller, request, response, done);
}
void UserService_Stub::GetFriendsList(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::GetFriendsListRequest* request,::fixbug::GetFriendsListResponse* response,::google::protobuf::Closure* done) {channel_->CallMethod(descriptor()->method(1),controller, request, response, done);
}
可以看见这个类没有无参构造,有几个RpcChannel*参数传递的构造方法,,不妨看看RpcChannel类:
class PROTOBUF_EXPORT RpcChannel {public:inline RpcChannel() {}virtual ~RpcChannel();// Call the given method of the remote service. The signature of this// procedure looks the same as Service::CallMethod(), but the requirements// are less strict in one important way: the request and response objects// need not be of any specific class as long as their descriptors are// method->input_type() and method->output_type().virtual void CallMethod(const MethodDescriptor* method,RpcController* controller, const Message* request,Message* response, Closure* done) = 0;private:GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcChannel);
};
很显然,这是个抽象基类,需要用户自己实现派生类重写基类的CallMethod方法
在之后login和GetFriendsList两个方法基本调用方式一样,都是通过_channel调用CallMethod方法执行对应rpc调用,那么可知UserService_Stub是服务消费者(Caller)
如何发布一个本地rpc服务?
#include <iostream>
#include <string>
#include "user.pb.h"
class UserService : public fixbug::UserServiceRpc //使用rpc服务发布端(rpc服务提供者)
{
public:bool Login(std::string name, std::string pwd){std::cout<<"doing local service : Login" << std::endl;std::cout<< "name:" << name << "pwd :" << pwd << std::endl;} /*** 重写基类UserServiceRpc的虚函数 下面这些方法都是框架直接调用的* caller ===> Login(LoginRequest) ==> transmit ==> callee* callee ===> Login(LoginRequest) ===> 调用下述的Login方法* */void Login(::google::protobuf::RpcController* controller,const ::fixbug::LoginRequest* request,::fixbug::LoginResponse* response,::google::protobuf::Closure* done){//框架给业务上报了请求参数LoginRequest 应用获取相应数据做本地业务std::string name = request->name();std::string pwd = request->pwd();//本地业务bool res = Login(name, pwd);//把响应写入 包括错误码、错误消息、返回值response->set_success(0);fixbug::ResultCode* rc = response->mutable_result();rc->set_errcode(0);rc->set_errmsg("");//执行回调操作 执行响应对象数据的序列化和网络发送(由框架来完成)done->Run();}
};
继承对应的UserServiceRpc服务提供者,重写其基类方法即可。
上面只是发布过程,具体rpc调用待续。。。
相关文章:
protobuf入门实践2
如何在proto中定义一个rpc服务? syntax "proto3"; //声明protobuf的版本package fixbug; //声明了代码所在的包 (对于C来说就是namespace)//下面的选项,表示生成service服务类和rpc方法描述, 默认是不生成的 option cc_generi…...
adb shell使用总结
文章目录 日志记录系统概览adb 使用方式 adb命令日志过滤按照告警等级进行过滤按照tag进行过滤根据告警等级和tag进行联合过滤屏蔽系统和其他App干扰,仅仅关注App自身日志 查看“当前页面”Activity文件传输截屏和录屏安装、卸载App启动activity其他 日志记录系统概…...
UG NX二次开发(C++)-Tag的含义、Tag类型与其他的转换
文章目录 1、前言2、Tag号的含义3、tag_t转换为int3、TaggedObject与Tag转换3.1 TaggedObject定义3.2 TaggedObject获取Tag3.3 根据Tag获取TaggedObject4.Tag与double类型的转换1、前言 在UG NX中,每个对象对应一个tag号,C++中,其类型是tag_t,一般是5位或者6位的int数字,…...
Informer 论文学习笔记
论文:《Informer: Beyond Efficient Transformer for Long Sequence Time-Series Forecasting》 代码:https://github.com/zhouhaoyi/Informer2020 地址:https://arxiv.org/abs/2012.07436v3 特点: 实现时间与空间复杂度为 O ( …...
c语言位段知识详解
本篇文章带来位段相关知识详细讲解! 如果您觉得文章不错,期待你的一键三连哦,你的鼓励是我创作的动力之源,让我们一起加油,一起奔跑,让我们顶峰相见!!! 目录 一.什么是…...
FFmpeg aresample_swr_opts的解析
ffmpeg option的解析 aresample_swr_opts是AVFilterGraph中的option。 static const AVOption filtergraph_options[] {{ "thread_type", "Allowed thread types", OFFSET(thread_type), AV_OPT_TYPE_FLAGS,{ .i64 AVFILTER_THREAD_SLICE }, 0, INT_MA…...
CAN学习笔记3:STM32 CAN控制器介绍
STM32 CAN控制器 1 概述 STM32 CAN控制器(bxCAN),支持CAN 2.0A 和 CAN 2.0B Active版本协议。CAN 2.0A 只能处理标准数据帧且扩展帧的内容会识别错误,而CAN 2.0B Active 可以处理标准数据帧和扩展数据帧。 2 bxCAN 特性 波特率…...
软工导论知识框架(二)结构化的需求分析
本章节涉及很多重要图表的制作,如ER图、数据流图、状态转换图、数据字典的书写等,对初学者来说比较生僻,本贴只介绍基础的轮廓,后面会有单独的帖子详解各图表如何绘制。 一.结构化的软件开发方法:结构化的分析、设计、…...
[SQL挖掘机] - 算术函数 - abs
介绍: 当谈到 SQL 中的 abs 函数时,它是一个用于计算数值的绝对值的函数。“abs” 代表 “absolute”(绝对),因此 abs 函数的作用是返回一个给定数值的非负值(即该数值的绝对值)。 abs 函数接受一个参数&a…...
vue拼接html点击事件不生效
vue使用ts,拼接html,点击事件不生效或者报 is not defined 点击事件要用onclick 不是click let data{name:测,id:123} let conHtml <div> "名称:" data.name "<br>" <p class"cursor blue&quo…...
【Spring】Spring之依赖注入源码解析
1 Spring注入方式 1.1 手动注入 xml中定义Bean,程序员手动给某个属性赋值。 set方式注入 <bean name"userService" class"com.firechou.service.UserService"><property name"orderService" ref"orderService"…...
【微软知识】微软相关技术知识分享
微软技术领域 一、微软操作系统: 微软的操作系统主要是 Windows 系列,包括 Windows 10、Windows Server 等。了解 Windows 操作系统的基本使用、配置和故障排除是非常重要的。微软操作系统(Microsoft System)是美国微软开发的Wi…...
12.python设计模式【观察者模式】
内容:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变的时候,所有依赖于它的对象得到通知并被自动更新。观者者模式又称为“发布-订阅”模式。比如天气预报,气象局分发气象数据。 角色: 抽象主题…...
重生之我要学C++第五天
这篇文章主要内容是构造函数的初始化列表以及运算符重载在顺序表中的简单应用,运算符重载实现自定义类型的流插入流提取。希望对大家有所帮助,点赞收藏评论,支持一下吧! 目录 构造函数进阶理解 1.内置类型成员在参数列表中的定义 …...
复习之linux高级存储管理
一、lvm----逻辑卷管理 1.lvm定义 LVM是 Logical Volume Manager(逻辑卷管理)的简写,它是Linux环境下对磁盘分区进行管理的一种机制。 逻辑卷管理器(LogicalVolumeManager)本质上是一个虚拟设备驱动,是在内核中块设备和物理设备…...
HuggingGPT Solving AI Tasks with ChatGPT and its Friends in Hugging Face
总述 HuggingGPT 让LLM发挥向路由器一样的作用,让LLM来选择调用那个专业的模型来执行任务。HuggingGPT搭建LLM和专业AI模型的桥梁。Language is a generic interface for LLMs to connect AI models 四个阶段 Task Planning: 将复杂的任务分解。但是这里…...
java工程重写jar包中class类覆盖问题
结论:直接在程序中复写jar中的类即可 原因:一般我java工程是运行在tomcat容器中,tomcat容易在加载我们工程类和jar包是的优先级为: 我们工程的class 先于 我们工程lib下的jar 重复的类只加载一次,加载我们复写后的类后…...
Mybatis基于注解与XML开发
文章目录 1 关于SpringBoot2 关于MyBatis2.1 MyBatis概述2.2 MyBatis核心思想2.3 MyBatis使用流程3 MyBatis配置SQL方式3.1 基于注解方式3.1.1 说明3.1.2 使用流程3.1.3 常用注解 3.2 基于XML方式3.2.1 相比注解优势3.2.2 使用流程3.2.3 常用标签 1 关于SpringBoot SpringBoot…...
数字化转型导师坚鹏:数字化时代扩大内需的8大具体建议
在日新月异的数字化时代、复杂多变的国际化环境下,扩大内需成为推动经济发展的国家战略,如何真正地扩大内需?结合本人15年的管理咨询经验及目前实际情况的深入研究,提出以下8大具体建议: 1、制定国民收入倍增计划。结…...
M1/M2 通过VM Fusion安装Win11 ARM,解决联网和文件传输
前言 最近新入了Macmini M2,但是以前的老电脑的虚拟机运行不起来了。😅,实际上用过K8S的时候,会发现部分镜像也跑不起来,X86的架构和ARM实际上还是有很多隐形兼容问题。所以只能重新安装ARM Win11,幸好微软…...
用Python复现论文里的CDSM融合:从NuScenes数据预处理到3D检测模型训练全流程
用Python复现论文里的CDSM融合:从NuScenes数据预处理到3D检测模型训练全流程自动驾驶感知系统的核心挑战在于如何有效融合多模态传感器数据。本文将手把手带你实现论文《CDSM: Cross-Domain Spatial Matching for Camera-Radar Fusion in 3D Object Detection》的核…...
浏览器扩展开发:打造个性化浏览体验
浏览器扩展开发:打造个性化浏览体验 什么是浏览器扩展? 浏览器扩展是一种可以增强浏览器功能的小型软件程序。 扩展类型 类型说明扩展程序完整功能的扩展主题自定义浏览器外观插件NPAPI 插件(已废弃) 扩展结构 my-extension/ ├─…...
兰亭妙微|UI设计外包中的UI图标设计核心技巧与设计师职业发展指南
在UI设计的视觉体系中,图标是传递信息的视觉语言,也是产品个性的关键载体。一枚富有设计感的图标,既能降低用户认知成本,又能让产品更具竞争力。北京兰亭妙微团队从工具选择、设计流程到个性表达,拆解UI图标创作的核心…...
图像增强与半监督学习在语义分割中的应用
1. 图像增强技术在语义分割中的应用原理计算机视觉领域的语义分割任务要求模型对图像中的每个像素进行分类,这需要模型具备强大的特征提取能力和泛化性能。图像增强技术通过人为引入数据多样性,成为提升模型鲁棒性的关键手段。在语义分割任务中ÿ…...
API安全设计与防护实战
API安全设计与防护实战 一、API安全概述 API作为系统间交互的接口,是攻击的主要目标。一个安全的API设计需要考虑多个层面的防护,包括认证、授权、数据保护、攻击防护等。 二、API认证机制 2.1 API Key认证 Component public class ApiKeyFilter ex…...
Codeforces Round 1057
【打得太糖了】Codeforces Round 1057 (Div. 2) solve 3 题 https://www.bilibili.com/video/BV1Gi4nzYE66/ 【Codeforces Round 1057 (Div. 2)实况】好久没打cf了,只会A-D https://www.bilibili.com/video/BV12q4xzMEy5/ 憧憬成为 Master 第 29 集 —— 反向冲分 (…...
AssetStudio深度解析:Unity序列化协议与产线级资源解包实战
1. 这不是“又一个AssetStudio教程”,而是我用它救回三个项目的真实记录AssetStudio、Unity资源提取、AssetBundle解包——这几个词,对做过Unity客户端开发、逆向分析、MOD制作或老游戏复刻的人来说,不是工具名,是救命稻草。我第一…...
感知机为什么必须加偏置?从数学本质到工程落地全解析
1. 为什么感知机神经元必须带偏置输入?——从数学本质到工程实践的全链路拆解“Why Perceptron Neurons Need Bias Input?” 这个标题看似简单,实则直击人工神经网络最基础却最容易被忽略的底层设计逻辑。我在带高校AI实验课、指导工业界图像分类项目落…...
【光学】偏振光线追迹Matlab仿真
✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、程序设计科研仿真。🍎完整代码获取 定制创新 论文复现点击:Matlab科研工作室👇 关注我领取海量matlab电子书和数学建模资料 dz…...
游戏模组革命:BepInEx框架让每个玩家都能打造个性化游戏体验
游戏模组革命:BepInEx框架让每个玩家都能打造个性化游戏体验 【免费下载链接】BepInEx Unity / XNA game patcher and plugin framework 项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx 想要为心爱的游戏添加新功能、修改游戏机制,或…...
