分布式网络通信框架(十)——Mprpc框架使用示例

发布一个服务提供远程调用方法的流程

若想要发布一个服务提供一些远程调用方法,步骤如下:

先在protobuf文件中添加参数和返回值的message 类型,然后再添加希望提供的服务 service 类型(如UserServiceRpc)和 其中的方法 rpc (如Login);

然后自己实现一个提供服务的.cc文件(如userservice.cc),重新写一个类(如UserService)继承自proto文件中 的service(即UserServiceRpc) ,并且重写对应的方法(从proto生成的.h文件中找函数的声明,如Login)

使用示例1

UserServiceRpc服务类中添加一个注册Registerrpc方法。

编写proto文件,让其生成对应的服务类(service)和服务方法成员,以及一些相关的消息(message)类型

// mprpc/example/user.proto
syntax = "proto3";

package fixbug;

option cc_generic_services = true;

message ResultCode
{
    int32 errcode = 1;
    bytes errmsg = 2;
}

// 定义登录消息类型
message LoginRequest
{
    bytes name = 1; // =1 代表name是这个message第一个字段,不是指name的值
    bytes pwd = 2;
}

// 定义登录响应消息
message LoginResponse
{
    ResultCode result = 1;
    bool success = 2;
}

message RegisterRequest
{
    uint32 id = 1;
    bytes name = 2; // =1 代表name是这个message第一个字段,不是指name的值
    bytes pwd = 3;
}

message RegisterResponse
{
    ResultCode result = 1;
    bool success = 2;
}
service UserServiceRpc
{
    rpc Login(LoginRequest) returns(LoginResponse);
    rpc Register(RegisterRequest) returns(RegisterResponse);
}

执行protobuf编译生成对应的c++代码:

protoc user.proto --cpp_out=./

服务发布方的业务代码中实现一个继承UserServiceRpc的类,并且在其中实现远程调用的目标函数,以及重写protobuf声明的目标方法的虚函数,并且在main函数中发布服务:

// mprpc/example/callee/userservice.cc
#include <iostream>
#include <string>
#include "user.pb.h"
#include "mprpcapplication.h"
#include "rpcprovider.h"

// UserService 是一个本地服务,提供了两个进程内的本地方法Login和GetFriendLists
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;
        return false;
    }

    bool Register(uint32_t id, std::string name, std::string pwd)
    {
        std::cout << "doing local service:Register" << std::endl;
        std::cout << "id" << id << "name:" << name << " pwd:" << pwd << std::endl;
    }
    // 这是在使用角度分析RPC的功能
    // 重写基类 UserServiceRpc的虚函数
    // 1. caller(client) ==> Login(LoginRequest) => muduo => callee(server)
    // 2. callee(server) ==> Login(LoginRequest) => 转发到重写的Login方法上(如下)
    void Login(::google::protobuf::RpcController *controller,
               const ::fixbug::LoginRequest *request,
               ::fixbug::LoginResponse *response,
               ::google::protobuf::Closure *done)
    {
        // 1.框架给业务上报了请求参数LoginRequest,应用获取相应数据做本地业务
        std::string name = request->name();
        std::string pwd = request->pwd();

        // 2.做业务
        bool login_result = Login(name, pwd);

        // 3.把响应写入
        fixbug::ResultCode *code = response->mutable_result();
        code->set_errcode(0);
        code->set_errmsg("");
        response->set_success(login_result);

        // 4.做回调操作,执行响应对象数据的序列化和网络发送(都是由框架完成)
        done->Run();
    }

    void Register(::google::protobuf::RpcController *controller,
                  const ::fixbug::RegisterRequest *request,
                  ::fixbug::RegisterResponse *response,
                  ::google::protobuf::Closure *done)
    {
        // 1.框架给业务上报了请求参数RegisterRequest,应用获取相应数据做本地业务
        uint32_t id = request->id();
        std::string name = request->name();
        std::string pwd = request->pwd();

        // 2.做业务
        bool register_result = Register(id, name, pwd);

        // 3.把响应写入
        fixbug::ResultCode *code = response->mutable_result();
        code->set_errcode(0);
        code->set_errmsg("");
        response->set_success(register_result);

        // 4.做回调操作,执行响应对象数据的序列化和网络发送(都是由框架完成)
        done->Run();
    }
};

int main(int argc, char **argv)
{
    // 调用框架的初始化操作
    MprpcApplication::Init(argc, argv);

    // provider是一个rpc网络服务对象,把UserService对象发布到rpc节点上
    RpcProvider provider;
    provider.NotifyService(new UserService());

    // 启动一个rpc服务发布节点,Run之后,进程进入阻塞状态,等待远程rpc调用请求
    provider.Run();
}

然后在客户端(服务调用方caller)业务代码中使用Stub对象来调用希望调用的方法,并且接收响应

// calluserservice.cc
#include <iostream>
#include "mprpcapplication.h"
#include "user.pb.h"
#include "mprpcchannel.h"

int main(int argc, char **argv)
{
    // 整个程序启动以后,想使用mprpc框架来享受rpc服务调用,一定需要先调用框架的初始化函数(只初始化一次)
    MprpcApplication::Init(argc, argv);

    // 演示调用远程发布的rpc方法Login
    fixbug::UserServiceRpc_Stub stub(new MprpcChannel());
    // rpc方法的请求参数
    fixbug::LoginRequest request;
    request.set_name("zhang san");
    request.set_pwd("123456");
    // rpc方法的响应
    fixbug::LoginResponse response;
    // 发起rpc方法的调用  同步的rpc调用过程  MprpcChannel::callmethod
    stub.Login(nullptr, &request, &response, nullptr); // RpcChannel->RpcChannel::callMethod 集中来做所有rpc方法调用的参数序列化和网络发送

    // 一次rpc调用完成,读调用的结果
    if (0 == response.result().errcode())
    {
        std::cout << "rpc login response success:" << response.sucess() << std::endl;
    }
    else
    {
        std::cout << "rpc login response error : " << response.result().errmsg() << std::endl;
    }

    // 演示调用远程发布的rpc方法Register
    fixbug::RegisterRequest req;
    req.set_id(2000);
    req.set_name("mprpc");
    req.set_pwd("666666");
    fixbug::RegisterResponse rsp;

    // 以同步的方式发起rpc调用请求,等待返回结果
    stub.Register(nullptr, &req, &rsp, nullptr); 

    // 一次rpc调用完成,读调用的结果
    if (0 == rsp.result().errcode())
    {
        std::cout << "rpc register response success:" << rsp.sucess() << std::endl;
    }
    else
    {
        std::cout << "rpc register response error : " << rsp.result().errmsg() << std::endl;
    }
    
    return 0;
}

使用示例2——新增加一个服务类,并且其中提供一个方法

新增一个好友服务(FriendServiceRpc),其中提供获取好友列表的rpc方法(FriendServiceRpc

首先编写protobuf文件

// mprpc/example/friend.proto
syntax = "proto3";

package fixbug;

option cc_generic_services = true;

message ResultCode
{
    int32 errcode = 1;
    bytes errmsg = 2;
}

message GetFriendsListRequest
{
    uint32 userid = 1;
}
message GetFriendsListResponse
{
    ResultCode result = 1;
    repeated bytes friends = 2; // 列表
}

service FriendServiceRpc
{
    rpc GetFriendsList(GetFriendsListRequest)   returns(GetFriendsListResponse);
}

实现服务发布方(callee)的业务代码

主要的工作就是实现一个新类继承于 UserServiceRpc,并且重写其对应的虚函数

// friendservice.cc
#include <iostream>
#include <string>
#include "friend.pb.h"
#include "mprpcapplication.h"
#include "rpcprovider.h"
#include <vector>

// FriendService 是一个本地服务,提供了两个进程内的本地方法Login和GetFriendLists
class FriendService : public FriendServiceRpc // 使用在rpc服务的发布端(rpc服务提供者)
{
public:
    std::vector<std::string> GetFriendsList(uint32_t userid)
    {
        std::cout << "do GetFriendList service! userid:" << userid << std::endl;
        std::vector<std::string> vec;
        vec.push_back("Jiang tao");
        vec.push_back("shao pin");
        vec.push_back("shao an");
        return vec;
    }

    // 重写基类方法
    void GetFriendsList(::PROTOBUF_NAMESPACE_ID::RpcController *controller,
                        const ::fixbug::GetFriendsListRequest *request,
                        ::fixbug::GetFriendsListResponse *response,
                        ::google::protobuf::Closure *done)
    {
        // 1.框架给业务上报了请求参数 GetFriendsListRequest ,应用获取相应数据做本地业务
        uint32_t userid = request->userid();
        // 2.做业务
        std::vector<std::string> friendsList = GetFriendsList(userid);

        // 3.把响应写入
        fixbug::ResultCode *code = response->mutable_result();
        code->set_errcode(0);
        code->set_errmsg("");
        for(std::string &name : friendsList)
        {
            std::string *p = response->add_friends();
            *p = name;
        }

        // 4.做回调操作,执行响应对象数据的序列化和网络发送(都是由框架完成)
        done->Run();
    }
};

int main(int argc, char **argv)
{
    // 调用框架的初始化操作
    MprpcApplication::Init(argc, argv);

    // provider是一个rpc网络服务对象,把UserService对象发布到rpc节点上
    RpcProvider provider;
    provider.NotifyService(new FriendService());

    // 启动一个rpc服务发布节点,Run之后,进程进入阻塞状态,等待远程rpc调用请求
    provider.Run();
    return 0;
}

实现服务发起调用(caller)方的代码

// callfriendservice.cc
#include <iostream>
#include "mprpcapplication.h"
#include "friend.pb.h"

int main(int argc, char **argv)
{
    MprpcApplication::Init(argc, argv);

    fixbug::FriendServiceRpc_Stub stub(new MprpcChannel());

    fixbug::GetFriendsListRequest request;
    request.set_userid(1000);
    fixbug::GetFriendsListResponse response;

    stub.GetFriendsList(nullptr, &request, &response, nullptr);

    if (0 == response.result().errcode())
    {
        std::cout << "rpc GetFriendsList Response success!" << std::endl;
        int size = response.friends_size();
        for (int i = 0; i < size; ++i)
        {
            std::cout << "index:" << i + 1 << " name:" << response.friends(i) << std::endl;
        }
    }
    else
    {
        std::cout << "rpc GetFriendsList Response error :" << response.result().errmsg() << std::endl;
    }

    return 0;
}

测试

编译时注意cmake文件

# mprpc/example/callee/CMakeLists.txt

set(SRC_LIST friendservice.cc ../friend.pb.cc)

# provider是目标文件,后面都是要链接的库 -lmprpc -lprotobuf

add_executable(provider ${SRC_LIST})

target_link_libraries(provider mprpc protobuf)
# mprpc/example/caller/CMakeLists.txt
set(SRC_LIST callfriendservice.cc ../friend.pb.cc)
# provider是目标文件,后面都是要链接的库 -lmprpc -lprotobuf
add_executable(consumer ${SRC_LIST})
target_link_libraries(consumer mprpc protobuf)

测试结果

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++内存管理和模板

文章目录 内存管理new和delete 函数模板隐式实例化显式实例化 类模板 内存管理 有时候我们需要动态的申请内存,比如队列,栈,二叉树等数据结构,我们一开始并不知道要存储多少个数据,也就是不确定究竟要多大的内存,给小了存不下,给大了会造成内存资源的浪费,因此动态的申请内存是…

原工程运行正常,重新复制一份后再 npm install 后再运行就报错的解决办法

原工程&#xff0c;运行正常 将刚刚的工程复制一份呢&#xff0c;重新 npm install 再 npm run serve 就报错 出现这个问题十之八九都是依赖的问题。有可能是因为这个工程里面之前安装过一些东西&#xff0c;后来莫名其妙的就把 package.json 里面相关的依赖给删掉了。但由于原…

【数据结构】顺序二叉树的实现—以堆的实现为例、堆的调整、堆的创建、堆的插入和删除、堆排序

文章目录 1.堆的概念及结构2.堆的实现&#xff08;以大堆为例&#xff09;2.1堆的插入2.1.1堆的向上调整算法 2.2堆的删除2.2.1堆的向下调整算法 2.3堆的创建2.4有关建堆的时间复杂度 3.堆排序4.C语言堆实现源码 1.堆的概念及结构 堆就是顺序结构二叉树。 如果有一个关键码的集…

jetcache参考文档

jetcache简介 https://github.com/alibaba/jetcache/blob/master/docs/CN/GettingStarted.md 简介 JetCache是一个基于Java的缓存系统封装&#xff0c;提供统一的API和注解来简化缓存的使用。 JetCache提供了比SpringCache更加强大的注解&#xff0c;可以原生的支持TTL、两级…

shell变量类型含义 长方形面积计算 截取相应字段方法

1.总结变量的类型及含义&#xff1f; 2.实现课堂案例计算长方形面积&#xff1f;&#xff08;6种方式&#xff09; 3.定义变量urlhttps://blog.csdn.net/weixin_45029822/article/details/103568815&#xff08;通过多种方法实现&#xff09; 1&#xff09;截取网站访问的协议 …

文心一言 VS 讯飞星火 VS chatgpt (22)-- 算法导论4.2 2题

二、为Strassen算法编写伪代码。 文心一言&#xff1a; Strassen算法是一种用于矩阵乘法的算法&#xff0c;它的核心思想是通过不断将原始矩阵分割成较小的子矩阵来实现高效的乘法运算。以下是Strassen算法的伪代码&#xff1a; function Strassen(A, B): if A[0][0] 0 or…

Springboot整合WebSocket

目录 1.WebSocket 简介 2.WebSocket 实战 1.WebSocket 简介 WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务端主动向客户端推送数据。在WebSocket API中&#xff0c;浏览器和服务器只需要…

基于html+css的图展示98

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

C++入门

文章目录 &#x1f600;1. 命名空间&#x1f604;1.1 命名空间定义&#x1f604;1.2 命名空间使用 &#x1f60a;2. 输入和输出&#x1f609;3. 缺省参数&#x1fae0;3.1 缺省参数概念&#x1fae0;3.2 缺省参数分类 &#x1f62c;4. 函数重载&#x1f644;4.1 函数重载概念&a…

TypeScript9-声明文件

本篇文章来讲 TypeScript 的声明文件。 当我们在使用第三方库的时候&#xff0c;很多第三方库不是用 TS 写的&#xff0c;它们是通过原生的 JavaScript 或者是浏览器 / 或者是 node 提供的 run time 对象。如果我们直接使用 TS 肯定就会报编译不通过。 1. 声明语句 假设一个…

浅析变电站无人值守管理的模式与特点

安科瑞虞佳豪 近年来&#xff0c;随着电网的发展&#xff0c;变电站实行无人值班管理模式已成为电网的发展方向。自1998年始&#xff0c;辉县市就开始了变电站综合自动化改造&#xff0c;截止目前全局所属24座变电站&#xff08;其中35kV19座、110kV5座&#xff09;已全部实现…

API自动化测试【postman生成报告】

PostMan生成测试报告有两种&#xff1a; 1、控制台的模式 2、HTML的测试报告 使用到一个工具newman Node.js是前端的一个组件&#xff0c;主要可以使用它来开发异步的程序。 一、控制台的模式 1、安装node.js 双击node.js进行安装&#xff0c;安装成功后在控制台输入node …

Java集合基础

4 集合基础 集合提供一种存储空间可变的存储模型,存储的数据容量可以改变ArrayLis<>: 可调整大小的数组实现<>:是一种特殊的数据类型,泛型可储存重复元素怎么使用呢 在出现E的地方我们使用引用数据类型替换即可举例:ArrayList<String>、ArrayList<Stu…

财务共享时代企业数智化应用能帮我们做些什么?

随着企业规模的不断扩大和业务范围的逐步扩展&#xff0c;财务工作的难度和复杂度也在不断提高&#xff0c;传统的手工录入和处理方式呈现出流程长、效率低、易出错等问题。为了提升财务工作的效率和准确性&#xff0c;越来越多的企业开始利用数智化应用打造企业内部的财务数智…

绝对不能错过的7个零基础免费的ChatGPT镜像网站

还在为打不开openai官网烦心&#xff1f;本文帮你实现ChatGPTMidJourney自由(&#xffe3;∇&#xffe3;)/ &#x1f4d2;收集了一些截至目前(2023年5月25日午12:00)可以免费访问&#xff0c;并且零基础也能正常使用的镜像网站&#xff0c;后续将持续维护更新(&#xff61;&a…

平安银行广州分行立足地域文化,增强差异化权益服务软实力

立足地域文化&#xff0c;拓展差异化权益服务 瓦屋纸窗之下&#xff0c;一盏清茶&#xff0c;三五好友&#xff0c;怡然自若。中国人对茶的喜爱由来已久&#xff0c;茶文化已成为中华传统文化中一张亮丽的名片&#xff0c;而广东茶文化则是中国四大茶文化系列之一。平安银行广州…

抖音seo优化源代码搭建+抖音小程序私有化开源部署

抖音seo优化源码&#xff0c;抖音seo矩阵系统搭建&#xff0c;抖音账号矩阵系统开发&#xff0c;企业在做账号矩阵过程中&#xff0c;最头疼的莫过于私域线索转化&#xff0c;作为开发者都知道&#xff0c;目前市面上我们了解的矩阵系统除了挂载POI信息外&#xff0c;无法挂载留…

unity四叉树和视锥体剔除

这个最好还是看代码&#xff0c;项目有注释放在这里&#xff1a; GetbadEarlyup/Quadtree-cone-scene: 这是一个unity四叉树场景视锥体剔除的Demo (github.com)https://github.com/GetbadEarlyup/Quadtree-cone-scene国内地址&#xff1a; Quadtree-cone-scene: unity四叉树和…

VESD静电监控系统:提高静电防护效果与管理效率

随着科学技术不断发展&#xff0c;现代的工业对静电防护的要求越来越高。因为静电的存在可能会对产品质量、工作环境、甚至是人身产生威胁。静电监控系统是一项高效的管理工具&#xff0c;能够有效地控制和监测静电产生的情况&#xff0c;提高静电防护效果和管理效率。 VESD静电…

U盘超级加密3000试用版与正式版的区别有哪些?

U盘超级加密3000是一款专业的U盘加密软件&#xff0c;它可以为U盘、移动硬盘、内存卡等移动存储设备加密。软件拥有正式版和试用版&#xff0c;那么这两个版本有什么区别呢&#xff1f;下面我们就一起来了解一下。 U盘超级加密3000试用版和正式版的区别 打开软件时的区别 试用…
最新文章