RpcProvider(rpc服务提供者)实现思路

这篇具有很好参考价值的文章主要介绍了RpcProvider(rpc服务提供者)实现思路。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

RpcProvider(服务提供者)实现思路

上一节说到,如何将一个本地服务发布成远程服务,但没有说明一个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();
    }
};

现在实现的发布服务方,那么显然Login方法是rpc框架帮我们调用的,什么时候调用?当rpc客户端通过网络发送rpc调用请求之后,这边接收到rpc请求,解析请求然后调用发布的服务方法,获取服务方法的响应在回传给rpc客户端即完成了一次远程rpc调用过程。
下面一一分析上面步骤的实现思路。
1、 首先,RpcProvider肯定是一个服务器,接收来自rpc客户端的请求,且能在一定程度上承载高并发的需求(考虑多个rpcClient给当前rpcProvider发送rpc调用请求)。显而易见RpcProvider需要一个高性能的网络库来做这些任务,那么可以考虑muduo网络库。
2、 网络库有了,用什么消息格式?–protobuf(优势就不赘述了)。 消息包含哪些内容?一个rpcclient发送请求过来调用一个远程方法,那么rpcProvider收到这个请求之后,能根据请求所携带的数据自动调用发布的rpc方法,那么请求必须包含服务名、方法名、以及参数,这样rpcProvider才知道怎么调用。即buffer = service_name + method_name + args
由于使用的是protobuf二进制消息存储,所以涉及到读取这几个参数的问题,可以将buffer加个4字节(int不会超过4字节)的head_size,head_size表示service_name和method_name的长度,这样可以先读取head_size,在根据head_size读取service_name+method_name。
最后读取args,思考一个问题,剩下的数据是不是都是args?不一定,考虑Tcp粘包的情况,一次接收到2个rpc调用请求,那么args也需要一个长度args_size来表示当前解析的rpc调用的参数长度。
因此这里借助protobuf定义一个消息格式即

message RpcHeader{
	bytes service_name = 1;
	bytes method_name = 2;
	uint32 args_size = 3;
}

那么header_size表示是该消息的长度,先读header_size,在读RpcHeader所包含的字节流,最后借助protobuf反序列化出这三个参数,那么得到了service_name 、method_name 、args_size。在接着读取args_size长度的字符流数据得到args。最后通过protobuf定义的参数格式反序列化出request。最终所需要的参数都已经拿到了。

3、 那么如何通过上面得到的参数自动调用rpc服务?首先得在本地存在这个远程服务,前面提到rpc框架来调用Login方法,那么 rpcProvider得预先对发布的 rpc方法做一下映射

struct ServiceInfo{
        google::protobuf::Service* m_service;  //保存服务对象
        std::unordered_map<std::string, const google::protobuf::MethodDescriptor*> m_methodMap; //保存服务的所有方法的映射关系
    };
    //存储注册成功的服务对象和其服务方法
    std::unordered_map<std::string, ServiceInfo> m_serviceMap; // service_name ---> ServiceInfo

例如UserService存在Login 和 Register两个方法, 由于UserService继承自UserServiceRpc ,那么可以借助protobuf来实现这预先实现这个映射。具体如下:

//框架提供给外部使用的,可以发布rpc方法的函数接口
void RpcProvider::NotifyService(google::protobuf::Service* service)
{

        ServiceInfo service_info;

        //获取服务对象的描述信息
        const google::protobuf::ServiceDescriptor *pserviceDesc = service->GetDescriptor();
        //获取服务的名字
        std::string service_name = pserviceDesc->name();
        //获取服务对象service的方法的数量
        int methodCnt = pserviceDesc->method_count();

        std::cout<< " service_name " << service_name << std::endl;

        for(int i = 0; i<methodCnt; ++i){
                //获取了服务对象指定下标的服务方法的描述(抽象描述) UserService Login
                const google::protobuf::MethodDescriptor *pmethodDesc = pserviceDesc->method(i);
                std::string method_name = pmethodDesc->name();
                service_info.m_methodMap.insert({method_name, pmethodDesc});

                std::cout<<" method_name: " << method_name << std::endl; 
        }

        service_info.m_service = service;
        m_serviceMap.insert({service_name, service_info});

}

RpcProvider可以借助这个方法注册一个rpc服务的站点,这样由RpcClient发送过来的rpc调用请求,通过muduo和protobuf解析得到上述几个参数之后,即可通过映射表调用指定的rpc服务。
即:

1、server_name, method_name, args= parse(buffer);  //解析参数
it = m_serviceMap.find(service_name);
method =  it->second.m_methodMap.find(method_name);
request = service->GetRequestPrototype(method).New();
2、request->ParseFromString(args_str) //序列化请求参数
response = service->GetResponsePrototype(method).New();
3、service->CallMethod(method, nullptr ,request, response, done); //调用具体的rpc方法  
---->  
4、最终调用:LoginLogin(::google::protobuf::RpcController* controller,
                       const ::fixbug::LoginRequest* request,
                       ::fixbug::LoginResponse* response,
                       ::google::protobuf::Closure* done)
--->
5、回调 done()

最后服务器调用完指定rpc方法后(此时response已填入响应),那么需要将respnse借助protobuf反序列化字节流数据,再通过muduo网络库发回给rpcClient,这就是done回调函数所做的事情。
即:

void done(fd, response)
{
   string response_str;
       if (response->SerializeToString(&response_str)) //将响应进行序列化
       {
               //序列化成功后,通过网络把rpc方法执行的结果发送给rpc的调用方
               fd->send(response_str);
       }
       fd->shutdown(); //模拟http的短链接服务, 由rpcprovider主动断开连接以免占用资源
}

到此RpcProvider基本实现。文章来源地址https://www.toymoban.com/news/detail-621716.html

到了这里,关于RpcProvider(rpc服务提供者)实现思路的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringCloud学习笔记(三)_服务提供者集群与服务发现Discovery

    既然SpringCloud的是微服务结构,那么对于同一种服务,当然不可能只有一个节点,需要部署多个节点 架构图如下: 由上可以看出存在多个同一种服务提供者(Service Provider) 搭建服务提供者集群 1、参考:SpringCloud 快速入门搭建单机版的:Eureka Server、Service Provider、Service Con

    2024年02月11日
    浏览(40)
  • 记一次dubbo消费者注册失败找不到服务提供者问题

    项目分多套环境,其中一套环境重新部署时,频繁出现消费者找不到服务提供者的错误 经过多次重启后才有可能恢复正常,而其他环境并没有发现此问题 怀疑点: 1.消费者和服务提供者dubbo版本对不上 2.服务提供者没有注册上服务 3.注册中心有问题 逐一排查: 1.消费者和服

    2023年04月18日
    浏览(40)
  • 简单步骤:Android studio 内容提供者 - 实现建立手机通讯录界面,读取系统联系人

    提示:本篇文章将会尽量保持精简,同时请诸位敲写代码时保持耐心,三连是最大的支持! 文章目录 前言 一、项目介绍 二、使用步骤 1.创建程序 2.添加 recyclerview-v7 库 3.放置界面控件 4.搭建界面布局 5.封装实体类 6.编写数据适配器 7.实现显示界面数据功能 8.去掉默认标题栏

    2024年02月08日
    浏览(57)
  • Java安全——安全提供者

    安全提供者 在Java中,安全提供者(Security Provider)是一种实现了特定安全服务的软件模块。它提供了一系列的加密、解密、签名、验证和随机数生成等安全功能。安全提供者基础设施在Java中的作用是为开发人员提供一种扩展和替换标准安全功能的方式,以满足特定的安全需

    2024年02月12日
    浏览(41)
  • 探索安卓内容提供者:构建、访问和管理数据【复习】

    内容提供者(ContentProvider)是Android系统四大组件之一,它是不同应用程序之间进行数据共享的标准API ,通过ContentResolver类可以访问ContentProvider中共享的数据。 ContentProvider的工作原理如下: A程序使用ContetntProvider暴露数据,才能被其他程序操作。B程序通过ContetnResolver操作A程序

    2024年02月10日
    浏览(37)
  • 移动应用开发实验-内容提供者-ContentResolver的使用

    本人将所学和前人的成果和经验结合,仅供学习和参考!!! 本文大部分源码内容有清晰的注释,请认真阅读! 通过线性布局和相对布局来搭建通讯录界面,界面效果如下图所示。创建布局文件contact_item.xml、导入界面图片、放置界面控件、创建条目界面的背景文件。创建

    2024年02月08日
    浏览(52)
  • dubbo启动报错 java.lang.reflect.InvocationTargetException null 没有提供者没有消费者

    启动dubbo时,控制台报错信息如下。 打开dubbo的服务注册中心发现 在网上查找了一番,网上的说发众说飞云,有人说要保证提供者和消费者的包名一致,也有人说是ip的问题要在host里面配置, 后来经过一番仔细查找发现不对的地方了 服务提供者的主类上没有配置注解,这个

    2024年02月13日
    浏览(48)
  • CSDN博客批量查询质量分https://yma16.inscode.cc/请求超时问题(设置postman超时时间)(接口提供者设置了nginx超时时间)

    https://yma16.inscode.cc/ 查询别人的一下子就返回了,查询我自己的,1分钟还不返回,然后就显示超时了。。 一开始我还以为是这个开源项目本身的问题,设置了请求超时时间,我还给它改了超时时间,后来发现不是的。。。 本来是100000的,我给改成1000000了,我对js代码不熟,

    2024年02月12日
    浏览(56)
  • Rpc服务消费者(Rpc服务调用者)实现思路

    前面几节说到Rpc消费者主要通过UserServiceRPc_Stub这个protobuf帮我们生成的类来实现,上代码回顾一下 UserServiceRpc_Stub可以看做是一个给用户提供rpc远程调用的代理类,这里面有rpcclient和rpcserver约定好的远程方法Login,Login方法是调用了一个channel_的callMethod方法,那么联想到其他服

    2024年02月14日
    浏览(34)
  • Golang 实现一个简单的 RPC 服务

    分享一个简单的 rpc 服务框架 一、服务端实现 二、客户端实现

    2024年04月10日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包