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

news2025/1/11 12:33:09

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

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

先在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.coloradmin.cn/o/580516.html

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

相关文章

傅里叶级数和傅里叶变换之间的关系推理及应用

傅里叶级数和傅立叶变换是傅里叶分析的两个主要工具&#xff0c;它们之间有密切的关系。 什么是傅里叶级数 傅里叶级数是将一个周期函数分解为一系列正弦和余弦函数的和。它适用于周期性信号&#xff0c;可以将周期函数表示为一组振幅和相位不同的谐波分量的和。傅里叶级数展…

【ChatGPT】ChatGPT快速生成短视频

1.chatGPT剪映 chatGPT生成文本后通过剪映图文成片 这次用了new bing&#xff1a;Chatbot AI 在线网页版 (atmob.cn) 打开剪映-图文成片 把new bing生成的文本粘贴过来&#xff0c;点击生成视频。 生成好了&#xff0c;是这样 剪映自动生成的&#xff0c;最后还是得手工改改&…

ChatGPT生成Excel统计公式

&#x1f34f;&#x1f350;&#x1f34a;&#x1f351;&#x1f352;&#x1f353;&#x1fad0;&#x1f951;&#x1f34b;&#x1f349; ChatGPT生成Excel统计公式 文章目录 &#x1f350;问题引入&#x1f350;具体操作&#x1f433;结语 &#x1f350;问题引入…

如何使用 service account 获取 keycloak 的用户信息

Keycloak 是一个开源的权限管理和认证系统。使用 Keycloak 可以让开发者专注于解决业务的核心问题。获取用户信息是权限管理和认证系统需要的基本功能。Service Account 是OAuth 2.0推荐的系统服务使用的账户&#xff0c;开发者可以通过 Keycloak 的 Service Account 来让自己的…

【嵌入式烧录/刷写文件】-3.2-S19/Hex文件转换为Bin文件

案例背景(共6页精讲)&#xff1a; 该篇将告诉您&#xff1a;如何使用Vector HexView工具&#xff0c;对一个Intel Hex或Motorola S-record(S19/SREC/mot/SX)文件转换为bin文件。 目录 1 Intel Hex&#xff0c;Motorola S-record(S19/SREC/mot/SX)&#xff0c;Bin文件之间的差…

基于SpringBoot养老院管理系统

目录 一、项目介绍 二. 运行环境 三、项目技术 四、部署项目 五、项目运行 六、项目展示 五、项目下载 一、项目介绍 基于springboot的养老院管理系统拥有多种角色账号&#xff1a;管理员和用户 管理员&#xff1a;管理员管理、用户管理、健康管理、病例方案管理、药品…

计算机网络面试八股文

网络分层结构 计算机网络体系大致分为三种&#xff0c;OSI七层模型、TCP/IP四层模型和五层模型。一般面试的时候考察比较多的是五层模型。最全面的Java面试网站&#xff1a;最全面的Java面试网站 五层模型&#xff1a;应用层、传输层、网络层、数据链路层、物理层。 应用层&a…

文生视频综述

文字生成视频当前挑战 和发展现状_哔哩哔哩_bilibili今天我们聊了什么是 text to video&#xff0c;它的原理和目前的研究进展。text to video 是一种将文本转换为视频的技术&#xff0c;它可以通过图像处理、语音识别和自然语言处理等技术来实现。目前&#xff0c;text to vid…

【C语言】刷题训练营 —— 每日一练(十三)

文章目录 前言 BC123 小乐乐找最大数BC124 小乐乐是否被叫家长BC125 小乐乐转换成绩BC126 小乐乐算多少人被请家长BC127 小乐乐算最高分BC128 小乐乐计算求和BC129 小乐乐计算函数BC130 小乐乐查找数字BC131 KiKi学程序设计基础BC132 KiKi算期末成绩完结 前言 大家好&#xff…

计算机体系结构标量处理机

先行控制技术 缓冲深度的设计方法 以先行指令缓冲栈为例。 假设缓冲深度为 D 1 D_1 D1​&#xff0c;考虑以下两种极端情况。 &#xff08;1&#xff09;先行指令缓冲栈已经充满&#xff0c;此时指令流出速度最快&#xff0c;例如连续分析RR型指令 &#xff0c;设这种指令序…

[元带你学: eMMC协议详解 12] Speed Mode 选择

依JEDEC eMMC 5.1及经验辛苦整理&#xff0c;付费内容&#xff0c;禁止转载。 所在专栏 《元带你学: eMMC协议详解》 内容摘要 全文 2000字&#xff0c; 介绍了各种Speed Mode 选择的方法&#xff0c; 需要按照一定的步骤&#xff0c; 重点需要掌握HS400, High Speed 和 HS20…

python中的流程控制语句

文章目录 if-else语句代码演示&#xff1a; if-elif-else语句代码演示1&#xff1a;代码演示2&#xff1a; while 循环语句循环语句练习1.求100以内所有的奇数之和2.求100以内所有7的倍数之和&#xff0c;以及个数3.求1000内的水仙花数4.获取用户输入的任意数&#xff0c;判断是…

《Reinforcement Learning: An Introduction》第2章笔记

2. Multi-armed Bandits 评估性反馈&#xff08;evaluative feedback&#xff09; 完全取决于采取的动作&#xff0c;这是强化学习采用的方式。纯粹的评估性反馈表明要执行的动作有多好&#xff0c;但是不关注它是否是可能的最好或最坏的动作。指导性反馈&#xff08;instruct…

迭代器Iterator和生成器funcion *

迭代器Iterator 迭代器 为各种不同的数据结果提供统一的访问机制&#xff0c;任何数据结构只要部署Iterator接口&#xff0c;就可以完成便利操作&#xff0c;主要提供for of 工作原理&#xff1a; 创建一个指针对象&#xff0c;指向当前数组的起始位置 第一次调用对象的next方…

JAVA之数组2

添加元素 从后往前进行迭代&#xff0c;最后在末尾插入元素 tip&#xff1a;为避免数字在覆盖过程中丢失&#xff0c;故从后往前覆盖 删除元素 从前往后迭代&#xff0c;最后将末尾赋值为0 tip: 以覆盖的数arr【i】为基准&#xff0c;构造循环 共同处Tip: 范围均为【index1&…

子串--子字符串 0528

210102 201012 A1A2…An An…A2A1 如何做&#xff0c; 翻转的是21&#xff0c;因为2>1; 翻转的是210&#xff0c;因为2>0; 翻转的是2101&#xff0c;因为2>1&#xff1b; 翻转的是21010&#xff0c;因为2>0&#xff1b; 翻转的是210102&#xff0c;因为22且1&…

JavaScript 进阶 (二)

目录 深入对象 创建对象三种方式 构造函数 实例成员&静态成员 内置构造函数 Object Array String Number 深入对象 创建对象三种方式 1. 利用对象字面量创建对象 const obj { name : abc} 2. 利用 new Object 创建对象 const obj new Object({ uname: 123 }…

如何评估一个好的物业系统开发方案?

在当前不断变化的物业管理市场中&#xff0c;物业系统已成为物业管理公司提高管理效率和降低成本的必然选择。因此&#xff0c;如何评估一个好的物业系统开发方案成为了每个物业管理决策者必须面对的重要问题。在本文中&#xff0c;我们将介绍如何从以下几个方面来评估一个好的…

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

六、用Strassen 算法作为子进程来进行一个 knn 矩阵和一个nkn 矩阵相乘&#xff0c;最快需要花费多长时间?对两个输入矩阵规模互换的情况&#xff0c;回答相同的问题。 文心一言&#xff1a; Strassen 算法是一种用于矩阵乘法的分治算法&#xff0c;它将原始的矩阵分解为较小…

腾讯云产品首单特惠是什么意思?包括新用户老用户的解答

腾讯云最近推出的活动限制条件为产品首单特惠&#xff0c;但是有的用户购买不了&#xff0c;右上角提示“产品首单特惠”&#xff0c;那么什么是产品首单特惠&#xff1f;什么是新用户&#xff1f;什么是老用户&#xff1f;新手站长给大家&#xff1a; 腾讯云产品首单特惠是什…