基于Protobuf的RPC

news2024/11/15 11:04:29

先上UserServer提供服务的函数要求proto文件内容:

syntax="proto3";
package fixbug;
option cc_generic_services=true;
message LoginRequest
{
    bytes name=1;
    bytes pwd=2;
}
message LoginResponse
{
    ResultCode result=1;
    bool sucess=2;
}
#调用远程服务的入口
service UserServiceRpc
{
    rpc Login(LoginRequest)returns(LoginResponse);
}

proto内容的解释:1.message类属性 2.service是一个抽象接口

接口类,也就是纯虚函数

Service:抽象接口由UserServiceRPC 和UserServiceRPC_Shub

这两个抽象类实现

UserServiceRPC:也就是Server端的服务的入口

UserServiceRPC_Shub:就是Client端请求服务的入口

下面直接源码:

class PROTOBUF_EXPORT Service {
 public:
  inline Service() {}
  virtual ~Service();
  enum ChannelOwnership { STUB_OWNS_CHANNEL, STUB_DOESNT_OWN_CHANNEL };
   //能够通过Service->GetDescriptor()得到派生类的ServerService的服务名和方法名
  virtual const ServiceDescriptor* GetDescriptor() = 0;
  //这个函数是被调用的函数,method是被调用的方法描述符,method->GetMethodDescriptor()
  //能够拿到方法的名字以及method->service()拿到对应的服务
  //Controller用于实现对于整个RPC的状态的控制,比如调用失败,就终止调用
  // request即调用方法的参数,response即调用方法的返回值
  //Clouser一个抽象的回调函数接口
  virtual void CallMethod(const MethodDescriptor* method,
                          RpcController* controller, const Message* request,
                          Message* response, Closure* done) = 0;
   //通过基类指针拿到派生类的Request
   virtual const Message& GetRequestPrototype(
      const MethodDescriptor* method) const = 0;
   //通过基类指针拿到派生类的Response
   virtual const Message& GetResponsePrototype(
      const MethodDescriptor* method) const = 0;
}

RpcController的代码,也是一个接口函数

class PROTOBUF_EXPORT RpcController {
 public:
  inline RpcController() {}
  virtual ~RpcController();
  virtual void Reset() = 0;
  virtual bool Failed() const = 0;
  virtual std::string ErrorText() const = 0;
  virtual void StartCancel() = 0;
  virtual void SetFailed(const std::string& reason) = 0;
  virtual bool IsCanceled() const = 0;
  virtual void NotifyOnCancel(Closure* callback) = 0;
}

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);
};

比较重要的,需要通过这个来完成Client调用,即

上面的几个重要的接口类,介绍完,那我们回到我们要做的内容 

UserServiceRPC 和UserServiceRPC_Shub 

这两个类经过proto自己生成的类,根据规定rpc UserserviceRpc(request)returns{response}

class UserServiceRpc : public ::google::protobuf::Service {
 protected:
  inline UserServiceRpc() {};
 public:
  virtual ~UserServiceRpc();
  typedef UserServiceRpc_Stub Stub;
  static const ::google::protobuf::::ServiceDescriptor* descriptor();
  virtual void Login(::google::protobuf::::RpcController* controller,
                       const ::fixbug::LoginRequest* request,
                       ::fixbug::LoginResponse* response,
                       ::google::protobuf::Closure* done);
  // implements Service ----------------------------------------------
  const ::google::protobuf::::ServiceDescriptor* GetDescriptor();
  void CallMethod(const ::google::protobuf::MethodDescriptor* method,
                  ::google::protobuf::RpcController* controller,
                  const ::google::protobuf::Message* request,
                  ::google::protobuf::Message* response,
                  ::google::protobuf::Closure* done);
  const ::google::protobuf::Message& GetRequestPrototype(
    const ::google::protobuf::MethodDescriptor* method) const;
  const ::google::protobuf::Message& GetResponsePrototype(
    const ::google::protobuf::MethodDescriptor* method) const;
 private:
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UserServiceRpc);
};



class UserServiceRpc_Stub : public UserServiceRpc {
 public:
  //这个UserServiceRpc_Stub,通过RpcChannel对象进行构造,目的是在RpcChannel的派生类中
  //直接调用派生类处理的函数
  UserServiceRpc_Stub(::google::protobuf::RpcChannel* channel);
  UserServiceRpc_Stub(::google::protobuf::RpcChannel* channel,
                   ::google::protobuf::Service::ChannelOwnership ownership);
  ~UserServiceRpc_Stub();
  inline ::PROTOBUF_NAMESPACE_ID::RpcChannel* channel() { return channel_; }
  // implements UserServiceRpc ------------------------------------------
  void Login(::google::protobuf::RpcController* controller,
                       const ::fixbug::LoginRequest* request,
                       ::fixbug::LoginResponse* response,
                       ::google::protobuf::Closure* done);
 private:
  ::google::protobuf::RpcChannel* channel_;
  bool owns_channel_;
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UserServiceRpc_Stub);
};

上述重点看一下:login和callback,

login:就是我们定义的rcp service,

CallBack:就是Client调用函数后的内容

区别:通过上面两个类,我们可以很明显的发现,UserServiceRpc有回调函数,UserServiceRpcSthub明显没有一个CallBack的回调函数。因此,可以知道RPC服务的过程。

但是,我们请求RCP服务必定是要有回调的,Client发起请求同样RPC要给Client一个回调,Server执行login并执行回调,这个执行的回调函数,就是通过实现RpcChannel的派生类来调用的

总结: 

Service、Controller、RpcChannle 我们可以简单的描述成下面的过程:

1.调用本地的login调用UserServiceRpc_Stub的login

2.new一个UserServiceRpc_Stub,并用SubRpcChannel初始化

3.执行回调函数,并序列化成规定的格式:比如:header_size+header_str(service_name、method_name)+args_size+args_str。然后,直接通过网络发送出去。

4.将header_size+header_str(service_name、method_name)+args_size+args_str规定的编解码格式解码成对应的service,method,agrs.

5.provider上述的service,method,agrs,然后通过提前将UserServiceRpc(继承Service)提前发布的方法,通过参数名直接找到对应的service,method,args

6.执行Userservice继承UserServiceRpc,实现提供的服务,并返回值

7.将派生类返回的值交给基类

8.将基类拿到的response序列化成二进制交给provider,并直接交给网络

9.将拿到的二进制,反序列化成response

10.执行RpcChannle的CallBack函数,将response返回给UserServiceRpc_Stub

11.UserServiceRpc_Stub执行Login函数

12.Client调用UserServiceRpc_Stub的函数

 

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

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

相关文章

JAVA游戏源码:跑酷|大学生练手项目

学习java朋友们,福利来了,今天小编给大家带来了一款跑酷源码。注意:此源码仅供学习使用!! 源码搭建和讲解 启动main入口: //************************************************************************ // ************完整源码…

AcWing食物链

Q1:怎么判断X和Y是不是同类? A:判断这俩是不是在一个集合中,如果在同一个集合中,那么判断X到祖先节点的距离D[X]和D[Y]到祖先节点的距离是否有D[X]%3D[Y]%3,也就是3同余 若果是,那么是同类。如果X和Y不在一个集合里面,那么把X和Y…

护网总结汇报PPT一键生成,还要啥售前工程师

【文末送:技战法】 干技术的,特别是干安服的,你让我日个站觉得没问题,你让我写个文档我挠挠头,抓抓背也能凑一篇,但是你要让我写个ppt,那我觉得你在为难我。 报告我都写好了,为啥还…

Eclipse Debug 配置

创建和使用 Debug 配置 Eclipse Debug 配置类似于运行配置但它是用于在调试模式下开启应用。 打开 Debug 配置对话框步骤为:Run > Debug Configurations 。 从左侧列表中选择 "Java Application" 选项来选择要调试的 Java 代码。 对话框中的描述信息…

24年电赛——自动行驶小车(H题)MSPM0G3507-编码电机驱动与通用PID

一、编码电机驱动 编码电机的详情可以查看此篇文章: stm32平衡小车--(1)JGB-520减速电机tb6612(附测试代码)_jgb520-CSDN博客 简单来说,编码电机的驱动主要是给一个 PWM 和一个正负级就能驱动。PWM 的大小…

AI PC处理器架-低功耗、NPU算力、大模型

AI PC处理器架构变化:ARM低功耗、引入NPU算力、大模型落地端侧 ARM架构以简洁的指令集设计,快速执行每条命令,实现低功耗下的高效性能。其核心理念是节能和效率,为电池驱动设备提供了理想选择。相较之下,x86架构虽指令…

Linux--shell脚本语言—/—<1>

一、shell简介 Shell是一种程序设计语言。作为命令语言,它交互式解释和执行用户输入的命令或者自动地解释和执行预先设定好的一连串的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构&am…

【practise】大数相加、大数相乘

通常,我们的int、long long类型都有最大的数字上限,也就是说再大了会有溢出问题,那么很大的数字是怎么进行运算的呢? 其中一种方法是把很大的数字转变成字符串存放到string中,然后用代码对字符串进行处理,…

PHP最新可用获取QQ昵称API接口源码_非第三方

PHP最新可用获取QQ昵称API接口源码,运行环境为php7-8都可以,内容为直接调用QQ空间接口 在需要展示QQ昵称处,直接调用以下函数就可以。 例如:get_qq_nick(123456)就会直接输出123456的qq号昵称。 API源码下载:QQ昵称AP…

【C语言】字符函数和字符串函数详解

🦄个人主页:小米里的大麦-CSDN博客 🎏所属专栏:https://blog.csdn.net/huangcancan666/category_12718530.html 🎁代码托管:黄灿灿 (huang-cancan-xbc) - Gitee.com ⚙️操作环境:Visual Studio 2022 目录 一、引言 内容一览 一、strlen …

一拖三无线充底座-带给你极致的便利生活

随着科技的不断进步,无线充电技术已经逐渐渗透到我们日常生活的方方面面,一拖三无线充底座作为其中的佼佼者,以其高效、便捷的特点受到广大用户的青睐。本文将从电磁感应原理、多线圈设计、频率匹配、电能传输、功率分配以及充电管理六个方面…

【Rust日报】终端表格查看工具

[new ver] Tabiew v0.6.1 Tabiew 是一个轻量级的、基于终端的应用程序,用于查看和查询分隔符分隔值格式的文档,例如 CSV 或 TSV 文件。 功能如下: 📊 表格视图: 通过易于导航的表格视图来探索数据。🔍 工作表视图: 深入…

深入剖析隐私安全测试:在数字化时代的守护者

大家好,我是一名_全栈_测试开发工程师,已经开源一套【自动化测试框架】和【测试管理平台】,欢迎大家关注我,和我一起【分享测试知识,交流测试技术,趣聊行业热点】。 一、引言 在日新月异的数字化浪潮中&…

FPGA开发——基于Quartus的工程建立以及下载仿真全过程

一、概述 在使用了这么久的FPGA之后,才发现前面光发了各个设计的设计文件和测试问价,还没有发过怎么利用我们编写的代码进行仿真和使用软件进行工程建立和下载验证的过程,今天就补发一篇Quartus的工程建立以及下载仿真全过程。 二、文件夹建…

程序执行的环境和预处理

目录: 思维导图 一 程序的翻译环境 二 程序的执行环境 三 C 语言程序的编译和链接 四 预定义符号 五 预处理指令 六 宏和函数对比 七 预处理操作符# 和 ## 八 命令定义 九 预处理指令#include 十 预处理指令#undef 十一 条件编译 WeChat_2024073122290…

JavaScript 打印 V 和倒 V 图案的程序(Program to print V and inverted-V pattern)

倒 V 型模式:给定 n 的值,打印倒 V 型模式。示例: 输入:n 5 输出 : E D D C C B B A A 输入:n 7 输出 : G F F E E D D C C B B A…

中药养发护发

按照中医理论,头发和肝肾有密切联系,肝主血,肾藏精, 其华在发,肝肾强健,上荣于头,则毛发乌黑浓密. 中药育发的应用 以当归,天麻,桑疹子养血润发,配合干姜祛风活血,能通畅经络, 加快循环,激活毛囊,能促进皮肤组织营养成分吸收和废弃物的排泄,改善 头发生态. 用苦参 皂角 清热化…

yum仓库的制作与使用

目录 前言: 1 查看系统内核 2 获取网络源 3 搭建yum网络仓库 4 rpm包的下载 4.1 将rpm包下载至本地 4.2 对下载的rpm包进行备份 5 制作本地yum源 5.1 软件仓库制作工具createrepo 5.2 使用createrepo创建本地yum仓库 6 搭建docker本地仓库 前言&#x…

【Dash】使用 HTML 和 CSS 创建图表

一、Styling Your App The examples in the previous section used Dash HTML Components to build a simple app layout, but you can style your app to look more professional. This section will give a brief overview of the multiple tools that you can use to enhan…

Scalable Diffusion Models with Transformers(DIT)代码笔记

完整代码来源:DiT DiT模型主要是在diffusion中,使用transformer模型替换了UNet模型,使用class来控制图像生成。 根据论文,模型越大,patch size 越小,FID越小。 模型越大,参数越多,pa…