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…...

String字符串拼接
String字符串拼接 1.简介2.StringBuilder2.1StringBuilder介绍2.2使用说明 3.StringBuffer4.StringJoiner5.String.Join() 1.简介 对于String来说是不可变的,使用修改字符串是在不断地创建新的字符串对象,而不是在原有的对象上修改的。并且对于字符串的…...

在矩池云使用Llama2-7B的具体方法
今天给大家分享如何在矩池云服务器使用 Llama2-7b模型。 硬件要求 矩池云已经配置好了 Llama 2 Web UI 环境,显存需要大于 8G,可以选择 A4000、P100、3090 以及更高配置的等显卡。 租用机器 在矩池云主机市场:https://matpool.com/host-m…...

API教程:轻松上手HTTP代理服务!
作为HTTP代理产品供应商,我们为您带来一份详细的教程,帮助您轻松上手使用API,并充分利用HTTP代理服务。无论您是开发人员、网络管理员还是普通用户,本教程将为您提供操作指南和代码模板,确保您能够顺利使用API并享受HT…...

脑网络通信:概念、模型与应用——Brain network communication: concepts, models and applications
脑网络通信:概念、模型与应用 介绍神经系统是通信网络从图论到大脑网络通信大脑网络通信模型和测量的分类法路由协议最短路径路由导航扩散过程广播(可通信性)参数模型线性阈值模型偏向性随机游走最短路径集合当前和新兴的应用将大脑结构与功能关联起来认知和临床表型的个体间…...

Docker创建tomcat容器实例后无法访问(HTTP状态 404 - 未找到)
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...

oracle数据库dbLink的使用
Oracle的数据库链路(dbLink)是一种允许在两个不同的数据库实例之间进行通信和数据交换的功能。它可以让你在一个数据库中访问另一个数据库的对象和数据,就像它们属于同一个数据库一样。 创建一个link: CREATE public DATABASE LINK link_sco…...

Coremail中睿天下|2023年第二季度企业邮箱安全态势观察
7月24日,Coremail邮件安全联合中睿天下发布《2023第二季度企业邮箱安全性研究报告》,对2023第二季度和2023上半年的企业邮箱的安全风险进行了分析。 一、垃圾邮件同比下降16.38% 根据Coremail邮件安全人工智能实验室(以下简称AI实验室&#…...

ZooKeeper分布式锁、配置管理、服务发现在Java开发中的应用
ZooKeeper提供了多种功能,包括分布式锁、配置管理、服务发现、领导选举等。 下面是一些常见的ZooKeeper功能及其在Java中的应用示例代码。 分布式锁 import org.apache.zookeeper.*; import java.io.IOException; import java.util.concurrent.CountDownLatch;pu…...

openGauss学习笔记-27 openGauss 高级数据管理- JOIN
文章目录 openGauss学习笔记-27 openGauss 高级数据管理- JOIN27.1 交叉连接27.2 内连接27.3 左外连接27.4 右外连接27.5 全外连接 openGauss学习笔记-27 openGauss 高级数据管理- JOIN JOIN子句用于把来自两个或多个表的行结合起来,基于这些表之间的共同字段。 在…...

域名解析优先级
浏览器访问过程解析 访问网址——>首先在本地电脑看看hosts里面是否有域名对应IP地址,如何有直接访问对应IP, 如果没有,则联网询问DNS服务器(一般网卡那边都配置了DNS服务器IP) linux hosts 路径: w…...