Rpc服务消费者(Rpc服务调用者)实现思路
Rpc服务消费者(Rpc服务调用者)实现思路
前面几节说到Rpc消费者主要通过UserServiceRPc_Stub这个protobuf帮我们生成的类来实现,上代码回顾一下
class UserServiceRpc_Stub : public UserServiceRpc {public:UserServiceRpc_Stub(::PROTOBUF_NAMESPACE_ID::RpcChannel* channel);UserServiceRpc_Stub(::PROTOBUF_NAMESPACE_ID::RpcChannel* channel,::PROTOBUF_NAMESPACE_ID::Service::ChannelOwnership ownership);~UserServiceRpc_Stub();inline ::PROTOBUF_NAMESPACE_ID::RpcChannel* channel() { return channel_; }// implements UserServiceRpc ------------------------------------------void Login(::PROTOBUF_NAMESPACE_ID::RpcController* controller,const ::fixbug::LoginRequest* request,::fixbug::LoginResponse* response,::google::protobuf::Closure* done);private:::PROTOBUF_NAMESPACE_ID::RpcChannel* channel_;bool owns_channel_;GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UserServiceRpc_Stub);//xxx.pb.cc
void UserServiceRpc_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);
}
};
UserServiceRpc_Stub可以看做是一个给用户提供rpc远程调用的代理类,这里面有rpcclient和rpcserver约定好的远程方法Login,Login方法是调用了一个channel_的callMethod方法,那么联想到其他服务方法应该也是底层调用了这个函数(底层根据method的索引来区分具体的method),那么这个方法具体如何工作的?这个类需要接受一个RpcChannel类作为参数,看看RpcChannel类:
class PROTOBUF_EXPORT RpcChannel {public:inline RpcChannel() {}virtual ~RpcChannel();virtual void CallMethod(const MethodDescriptor* method,RpcController* controller, const Message* request,Message* response, Closure* done) = 0;private:GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcChannel);
};
很简单就是一个抽象类,有个纯虚函数CallMethod需要rpc_stub来实现。要实现rpcService_Stub,显然先需要具体化一个MyRpcChannel类,这个MyRpcChannel类继承自RpcChannel 类,最后通过多态调用在callMethod方法里面完成rpc远程调用的过程。那么具体怎么进行?
void UserServiceRpc_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);
}
Login方法接收4个参数,第一个controller先不用管,显然第四个参数done也不需要管因为作为rpc消费者不需要在将什么结果反馈给rpc提供者。那么就只需要传递两个参数,request即是rpc_stub封装用户端请求的参数,response即是在远程调用完成之后rpcserver帮rpcclient填写的,然后rpc_stub只需要反序列化出来结果反馈给用户即可,那么基本实现思路就有了:
step1:实现MyRpcchannel类,继承自RpcChannel ,并重写其CallMethod方法,CallMethod实现有如下几小步:
step1.1:获取具体服务名和方法名以及将用户传入的request序列化,最终封装成一个字符流(header_size + service_name method_name args_size + args_str)
//获取服务名和方法名const google::protobuf::ServiceDescriptor* service = method->service();std::string service_name = service->name(); //service_namestd::string method_name = method->name(); //method_name//获取参数的序列化字符串长度 args_sizestd::string args_str;uint32_t args_size = 0;if(request->SerializeToString(&args_str)){args_size = args_str.size();}else{std::cout << "request serlize error" << std::endl;return;}//定义rpc请求的HeaderRpcHeader rpcHeader;rpcHeader.set_service_name(service_name);rpcHeader.set_method_name(method_name);rpcHeader.set_args_size(args_size);std::string rpc_header_str;uint32_t header_size = 0;if(rpcHeader.SerializeToString(&rpc_header_str)){header_size = rpc_header_str.size();}else{std::cout << "rpcheader_str serlize error" << std::endl;return;}//组织待发送的rpc请求的字符串std::string send_rpc_str;send_rpc_str.insert(0, std::string((char*)&header_size, 4)); // header_sizesend_rpc_str += rpc_header_str; //rpcHeadersend_rpc_str += args_str; //args
step1.2:连接远程rpcServer服务器(可以是不同机器上的不同进程,也可以是在不同的机器上)
connect to rpcServer
step1.2:将封装的rpc字符流通过socket发送给RpcServer(远程rpc调用请求)
send----->send_rpc_str
step1.3:阻塞等待rpcServer的响应,并将响应饭序列化出来给用户端。
recv------>recv_buf
//反序列化rpc调用的响应数据std::string response_str(recv_buf, 0, recv_size);if(!response->ParseFromString(response_str)){std::cout<< "parse error ! response_str:" << response_str << std::endl;return;}
step2:用户创建UserServiceRpc_Stub类对象,并将MyRpcchannel实例对象传入进行构造。最后通过UserServiceRpc_Stub对象实例调用对应的rpc服务。(实际调用的就是上述实现的CallMethod方法)
fixbug::UserServiceRpc_Stub stub(new MyRpcChannel());//rpc方法的请求参数fixbug::LoginRequest request;request.set_name("zhang san");request.set_pwd("123");//rpc方法的响应,同步的rpc调用过程fixbug::LoginResponse response;stub.Login(nullptr, &request, &response, nullptr); //RpcChannel-->Rpchannel::callMethod 集中来做所有rpc方法调用的参数序列化和网络发送
step3:处理阻塞的响应消息response做相应的业务处理。
//一次rpc调用完成,读调用的结果if(0 == response.result().errcode()){std::cout << "rpc login response success: " << response.success() << std::endl;}else{std::cout << "rpc login error msg : " << response.result().errmsg() << std::endl;}
至此RpcConsumer基本实现。
相关文章:
Rpc服务消费者(Rpc服务调用者)实现思路
Rpc服务消费者(Rpc服务调用者)实现思路 前面几节说到Rpc消费者主要通过UserServiceRPc_Stub这个protobuf帮我们生成的类来实现,上代码回顾一下 class UserServiceRpc_Stub : public UserServiceRpc {public:UserServiceRpc_Stub(::PROTOBUF…...
FANUC机器人实现2个RO输出信号互锁关联(互补)的具体方法
FANUC机器人实现2个RO输出信号互锁关联(互补)的具体方法 一般情况下,为了方便用户控制工装夹具上的电磁阀等控制工具,FANUC机器人出厂时给我们提供了8个RO输出信号,如下图所示,这8个RO信号可以各自单独使用。 那么,如果为了安全控制,需要将2个RO信号成对的进行安全互锁…...
权威认可|云畅科技再次入选中国信通院「高质量数字化转型产品及服务全景图」
7月27日,由中国信通院主办的2023数字生态发展大会暨中国信通院“铸基计划”年中会议在北京成功召开。 会上,中国信通院重磅发布了「高质量数字化转型产品及服务全景图(2023)」,云畅科技凭借其自研产品「万应低代码」在…...
爬虫小白-如何调试列表页链接与详情链接不一样并三种方式js逆向解决AES-ECB
目录 一、网站分析二、定位监听三、熟悉AES-ECB四、调试分析五、node运行js六、Python执行js 一、网站分析 三年前的案例,我的原始文章网站 ,如图我们直接点击标题进入到详情页,链接会发生跳转,且与我们在详情看到的链接…...
Ubuntu 离线部署的常见操作
Ubuntu 离线安装的常见操作 **说明:**很多情况下,生产环境都是离线环境,然而开发环境都是互联网的环境,因此部署的过程中需要构建离线安装包; 1. 下载但是不安装 # 例如使用 apt 下载 wireshark 安装包 sudo apt download wireshark # 下载…...
什么是多运行时架构?
服务化演进中的问题 自从数年前微服务的概念被提出,到现在基本成了技术架构的标配。微服务的场景下衍生出了对分布式能力的大量需求:各服务之间需要相互协作和通信,以及共享状态等等,因此就有了各种中间件来为业务服务提供这种分…...
【MySQL】mysql | linux | 离线安装mysqldump
一、说明 1、项目要求离线安装mysqldump 2、数据库服务已经使用docker进行安装,但是其他项目依赖mysqldump,所以需要在宿主机上安装mysqldum 二、解决方案 1、下载依赖 https://downloads.mysql.com/archives/community/ 2、下载内容 mysql-community-c…...
中国农村程序员学习此【JavaScript教程】购买大平层,开上帕拉梅拉,迎娶白富美出任CEO走上人生巅峰
注:最后有面试挑战,看看自己掌握了吗 文章目录 在 Switch 语句添加多个相同选项从函数返回布尔值--聪明方法undefined创建 JavaScript 对象通过点号表示法访问对象属性使用方括号表示法访问对象属性通过变量访问对象属性给 JavaScript 对象添加新属性删除…...
【Python】Web学习笔记_flask(2)——getpost
flask提供的request请求对象可以实现获取url或表单中的字段值 GET请求 从URL中获取name、age两个参数 from flask import Flask,url_for,redirect,requestappFlask(__name__)app.route(/) def index():namerequest.args.get(name)agerequest.args.get(age)messagef姓名:{nam…...
RabbitMQ 教程 | 第5章 RabbitMQ 管理
👨🏻💻 热爱摄影的程序员 👨🏻🎨 喜欢编码的设计师 🧕🏻 擅长设计的剪辑师 🧑🏻🏫 一位高冷无情的编码爱好者 大家好,我是 DevO…...
LLM微调 | Adapter: Parameter-Efficient Transfer Learning for NLP
目的:大模型预训练+微调范式,微调成本高。adapter只只微调新增的小部分参数【但adapter增加了模型层数,引入了额外的推理延迟。】 Adapters最初来源于CV领域的《Learning multiple visual domains with residual adapters》一文,其核心思想是在神经网络模块基础上添加一些残…...
在idea中添加try/catch的快捷键
在idea中添加try/catch的快捷键 在idea中添加try/catch的快捷键 ctrlaltt 选中想被try/catch包围的语句,同时按下ctrlaltt, 出现下图 选择try/catch即可。...
企业级开发中协同开发与持续集成持续部署
文章目录 1 创建代码仓库2 使用git协同开发2.1 独立团队开发2.2 多团队开发git工作流 2 持续集成和持续部署2.1 创建docker镜像2.2 使用coding构建 1 创建代码仓库 每个项目有唯一的代码仓库,所以不是每个开发者都需要创建一个代码仓库,一般都是项目负责…...
九五从零开始的运维之路(其二十八)
文章目录 前言一、概述二、用户权限类型三、用户赋权四、权限删除五、用户删除六、刷新权限:七、修改用户密码总结 前言 本篇将简述的内容:Linux系统下的MySQL服务用户权限管理 一、概述 数据库用户权限管理是数据库系统中非常重要的一个方面ÿ…...
iOS--Runloop
Runloop概述 一般来说,一个线程一次只能执行一个任务,执行完成后线程就会退出。就比如之前学OC时使用的命令行程序,执行完程序就结束了。 而runloop目的就是使线程在执行完一次代码之后不会结束程序,而是使该线程处于一种休眠的状…...
Doccano工具安装教程/文本标注工具/文本标注自己的项目/NLP分词器工具/自然语言处理必备工具/如何使用文本标注工具
这篇文章是专门的安装教程,后续的项目创建,如何使用,以及代码部分可以参考这篇文章: NER实战:(NLP实战/命名实体识别/文本标注/Doccano工具使用/关键信息抽取/Token分类/源码解读/代码逐行解读)_会害羞的杨卓越的博客-…...
windows系统之WSL 安装 Ubuntu
WSL windows10 以上才有这个wsl功能 WSL: windows Subsystem for Linux 是应用于Windows系统之上的Linux子系统 作用很简单,可以在Windows系统中获取Linux系统环境,并完全直连计算机硬件,无需要通过虚拟机虚拟硬件 Windows10的W…...
洛谷题解 | P1046 陶陶摘苹果
目录 题目描述 输入格式 输出格式 输入输出样例 说明/提示 AC代码 题目描述 陶陶家的院子里有一棵苹果树,每到秋天树上就会结出 1010 个苹果。苹果成熟的时候,陶陶就会跑去摘苹果。陶陶有个 3030 厘米高的板凳,当她不能直接用手摘到苹果…...
记一次Apache HTTP Client问题排查
现象 通过日志查看,存在两种异常情况。第一种:开始的时候HTTP请求会报超时异常。 762663363 [2023-07-21 06:04:25] [executor-64] ERROR - com.xxl.CucmTool - CucmTool|sendRisPortSoap error,url:https://xxxxxx/realtimeservice/services/RisPort o…...
Linux获取文件属性
以-rw-rw-r-- 1 ubuntu ubuntu 56 八月 1 19:37 1.txt 为例 一、stat函数 功能:获取文件的属性 函数原型: #include <sys/types.h> #include <sys/stat.h> #include <unistd.h>int stat(const char *pathname, struct stat *stat…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...
给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...
