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

news/2024/11/8 0:39:02/

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

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

先在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方法Loginfixbug::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::callmethodstub.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方法Registerfixbug::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.txtset(SRC_LIST friendservice.cc ../friend.pb.cc)# provider是目标文件,后面都是要链接的库 -lmprpc -lprotobufadd_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.ppmy.cn/news/99878.html

相关文章

看完这篇Markdown你就会了

Markdown是一种轻量级标记语言&#xff0c;它的设计目标是让人们使用简单的语法快速地书写文本内容&#xff0c;并且可以转换为HTML等其他格式。Markdown的语法非常简单易学&#xff0c;只需要掌握几个基本的符号即可&#xff0c;相比于HTML等其他标记语言&#xff0c;Markdown…

如何正确地使用ES6提高我们的代码质量

前言 相信每个前端工程师&#xff0c;或者了解前端的人都知道ES6。它是js的一次巨变&#xff0c;它为我们开发js前端项目的时候带来了许多更好的去书写代码的方式。但是很多时候我们可能都没有过度地去关注优化代码这一块内容&#xff0c;哪怕有也只是注意到了一些比较大众化&…

K210入门-环境搭建与点灯测试(一)

目录 1、简介 2、资质查找 3、IDE下载安装 4、测试程序 4.1 测序复制 4.2 开发板选择 4.3 链接 4.4 效果展示 1、简介 本文主要针对小白使用K210进行入门&#xff0c;以及自己学习的总结与笔记使用。本文主要进行环境搭建与点灯测试。 2、资质查找 首先去官网进行资料下…

深度学习基本功3:NMS(Non-Maximum Suppression,非极大值抑制)算法原理及实现

文章目录 1. 为什么要使用NMS2. NMS算法原理2.1 IoU与置信度2.2 算法流程 3. Python代码实现 1. 为什么要使用NMS 大多数目标检测算法&#xff08;稠密预测&#xff09;在得到最终的预测结果时&#xff0c;特征图的每个位置都会输出多个检测结果&#xff0c;整个特征图上会出很…

14巧探细节:gRPC的UnknownService接口

gRPC UnknownServiceHandler是一个gRPC内置的一种拦截器,用于处理未知的服务请求。具体的使用案例可以是在服务端实现一个UnknownServiceHandler,当客户端请求一个不存在的服务时,服务端会返回一个自定义的错误信息,而不是默认的 gRPC 错误信息以提高服务的可读性。接下来让…

SPA首屏加载速度慢的怎么解决?

SPA首屏加载速度慢的怎么解决&#xff1f; 加载慢的原因 网络延时问题资源文件体积是否过大资源是否重复发送请求去加载了加载脚本的时候&#xff0c;渲染内容堵塞了 解决方案 1.减小入口文件体积 常用的手段是路由懒加载&#xff0c;把不同路由对应的组件分割成不同的代码…

上海城市开发者社区小聚有感

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是Rockey&#xff0c;不知名企业的不知名Java开发工程师 &#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&#x1f44d;一下博主哦 &#x1f4dd;联系方式&#xff1a;he18339193956&…

几句命令搞定一个es:docker安装elasticsearch+可视化kibana

docker安装elasticsearch可视化kibana 写在前面es安装&#xff1a;docker安装elasticsearches搜索&#xff1a;安装elasticsearch插件IK分词器es可视化&#xff1a;docker安装kibana最后 写在前面 从自己知道es开始到写这篇文章差不多也有5年左右的时间了吧&#xff0c;之前总…