基于Protobuf的RPC

server/2024/10/20 4:01:09/

先上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;//通过基类指针拿到派生类的Requestvirtual const Message& GetRequestPrototype(const MethodDescriptor* method) const = 0;//通过基类指针拿到派生类的Responsevirtual 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.ppmy.cn/server/95409.html

相关文章

Python数据库连接全解析:5大方案实战对比

在本文中,我们将通过实际示例,深入探讨Python中5种主流的数据库连接方案。这些例子将帮助您更好地理解每种方法的特点和适用场景。 目录 不同方案说明1. DB-API:以sqlite3为例2. SQLAlchemy:ORM示例3. psycopg2:Postgr…

美团2024年春招第一场笔试[测开方向],编程题+选择题详解,ACM式C++解法

编程题&选择题 编程题小美的平衡矩阵思路代码 小美的数组询问思路代码 验证工号思路代码 选择题1.在计算机网络中,端口号的作用是什么2.HTTPS协议通过使用哪些机制来确保通信的安全性3.Etag用于标识资源的唯一标识符,他可以用于4.在一个单道系统中&a…

深信服day9:文件后缀名和Cookie和前后端地址区别

一、文件后缀名 ISO:镜像文件 RAR:压缩包 html:网页 zip:压缩包 exe:可执行文件 pdf:pdf文档 rm:视频文件 avi:视频文件 tmp:临时文件 mdf:虚拟光驱…

ZeroMQ(二):请求-响应模式,C和C++。

目录 请求响应基础 基本概念 工作流程 典型应用 请求-响应模式的特点 应用实例 优点 缺点 ZEROMQ C语言 2.1 服务器端代码(Reply Server) 2.2 客户端代码(Request Client) 3. 编译代码 4. 详细说明 ZEROMQ C 1. …

鸿蒙媒体开发【相机数据采集保存】拍照和图片

相机数据采集保存 介绍 本示例主要展示了相机的相关功能 接口实现相机的预览拍照功能。 效果预览 使用说明 弹出是否允许“CameraSample”使用相机?点击“允许”弹出是否允许“CameraSample”使用麦克风?点击“允许”进入预览界面,预览正…

【BUG】jinja2.exceptions.TemplateNotFound

这段时间,陆陆续续在做一些开发,记录下,这个该死的bug,把人反反复复折磨了1个小时,最终以一种意想不到的方式解决了它。 任务:设置后端服务器,我创建一个server.py,用于设置 Flask 服…

Yolov8在RK3588上进行自定义目标检测(四)

参考 Yolov8在RK3588上进行自定义目标检测(一) Yolov8在RK3588上进行自定义目标检测(二) Yolov8在RK3588上进行自定义目标检测(三) YOLOV8火灾检测模型的边缘端推理 验证rknn模型 1.将转换好的rknn模型上传到板子上,再在板子上安装rknn-toolkit-lite2,将上面的…

C 环境设置

C 环境设置 C语言作为一种广泛使用的编程语言,其环境设置是每个开发者必须掌握的基本技能。本文将详细介绍如何在不同的操作系统上设置C语言开发环境,包括Windows、macOS和Linux系统。我们将涵盖安装编译器、配置开发环境以及编写和运行第一个C程序。 Windows系统上的C环境…