example文件夹作为我们框架项目的使用实例,在example文件夹下创建callee和caller两个文件夹,还包含用于生成rpc service的proto文件。
proto文件
在proto文件中我们使用了message和service两个关键词组,在编译proto文件时会将他们对应的内容都生成为相应的类,例如:UserService原来是一个本地服务,提供了进程内的本地方法:Login(),在proto文件中需要先在service类UserServiceRpc中注册Login()方法。然后对proto文件进行编译生成后会生成对应的.pb.h和.pb.cc文件,其中会将proto文件注册的service直接生成为对应的类。
syntax ="proto3";
package RPC;
option cc_generic_services=true;
//失败类
message ResultCode
{
int32 errcode=1;//错误代码
bytes errmsg=2;//错误消息
}
//登陆request
message LoginRequest
{
bytes name=1;//姓名
bytes pwd=2;//密码
}
//登陆response
message LoginResponse
{
ResultCode result=1;//失败类
bool success=2;//判断rpc执行成功还是执行失败
}
//注册request
message RegisterRequest
{
uint32 id=1;//账号
bytes name=2;//用户名
bytes pwd=3;//密码
}
//注册response
message RegisterResponse
{
ResultCode result=1;//失败类
bool success=2;//判断rpc执行成功还是执行失败
}
//用户模块的rpc service,里面包含两个rpc method
service UserServiceRpc
{
rpc Login(LoginRequest)returns(LoginResponse);
rpc Register(RegisterRequest)returns(RegisterResponse);
}
可以看到service已经生成了类,而他对应的Login()方法也已经生成了虚函数(生成虚函数的作用下边再说)。
callee文件夹
这个文件夹包含不同的rpc service文件,每个文件将不同的本地服务发布成rpc service。
//本地服务发布成RPC服务的方法
#include <iostream>
#include <string>
#include "../user.pb.h" //包含protobuf头文件
#include "mprpcapplication.h"
#include "mprpcprovider.h"
//using namespace RPC;
/*我的角色是服务的提供者,你作为远端想发起一个调用我这个机器上的UserService的Login方法
首先你会发一个RPC请求,这个请求是先到RPC框架,RPC框架根据你发过来的请求,然后根据参数和标识
匹配到我的Login方法,然后它就把这个网络上发的请求上报来,我接收到这个请求后,从请求中拿取数据,
然后做本地业务,填写相应的响应,然后再执行一个回调,相当于把执行完的这个RPC方法的返回值再塞给框架
,然后框架再进行序列化,通过网络传送回去,发送给你。体现在Login的四个参数。
*/
//RPC::UserServiceRpc有Login()和Register()的虚函数,UserService是一个本地类,需要重写这两个函数,以便于UserServiceRpc::CallMethod()调用
class UserService : public RPC::UserServiceRpc
{
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 Register service:Login" << std::endl;
std::cout << "id:" << id << " name:" << name << " pwd:" << pwd << std::endl;
return true;
}
/*
重写基类UserServiceRpc的 Login()和Register()虚函数,以下方法由UserServiceRpc::CallMethod()直接调用
1.caller远程调用者发起远程调用请求Login(LoginRequest)=>muduo=>callee
2.callee发现远程请求调用Login(LoginRequest)=>调用UserServiceRpc::CallMethod()=>调用下面的rpc method
各个参数的作用:
1.从LoginRequest获取参数的值
2.执行本地服务Login,并获取返回值
3.用上面的返回值填写LoginResponse
4.一个回调,把LoginResonse发送给发起RPC服务的主机
*/
void Login(::google::protobuf::RpcController *controller,
const ::RPC::LoginRequest *request,
::RPC::LoginResponse *response,
::google::protobuf::Closure *done)
{
//框架给业务上报了请求参数:LoginRequest,应用程序取出request中相应的已反序列化的数据来做本地业务
std::string name = request->name();
std::string pwd = request->pwd();
调用本地方法,实现rpc
bool loginresult = Login(name, pwd);
//把response写入,包括错误码,错误信息和运行结果
RPC::ResultCode *Code = response->mutable_result();
Code->set_errcode(0);
Code->set_errmsg("");
response->set_success(loginresult);
//执行回调函数RpcProvider::SendRpcResponse()
done->Run();
}
void Register(::google::protobuf::RpcController *controller,
const ::RPC::RegisterRequest *request,
::RPC::RegisterResponse *response,
::google::protobuf::Closure *done)
{
uint32_t id = request->id();
std::string name = request->name();
std::string pwd = request->pwd();
//开始做本地业务
bool ret = Register(id, name, pwd);
//填充回调结果
response->mutable_result()->set_errcode(0);
response->mutable_result()->set_errmsg("");
response->set_success(ret);
done->Run();
}
};
int main(int argc, char **argv)
{
//先调用框架的初始化操作 provider -i config.conf,从init方法读取配置服务,比如IP地址和端口号
MprpcApplication::Init(argc, argv);
//通过RpcProvider把UserService对象发布到rpc节点上
RpcProvider provider;
provider.NotifyService(new UserService()); //发布service
//启动一个rpc服务发布节点,Run以后,进程进入阻塞状态,等待远程的rpc请求
provider.Run();
return 0;
}
caller文件夹
caller文件夹下的文件使用callee发布的rpc service,调用rpc service里的rpc method。
//caller就是按照rpc服务方(callee)提供的proto协议,发起调用
#include "mprpcapplication.h"
#include "mprpcchannel.h"
#include "user.pb.h"
#include <iostream>
int main(int argc, char **argv)
{
//整个程序启动以后,想使用mprpc来获取rpc服务调用,一定需要先调用框架的初始化函数(只初始化一次)
MprpcApplication::Init(argc, argv);
//创建与所要使用的rpc相对应的service类对象
RPC::UserServiceRpc_Stub stub(new MprpcChannel);
//rpc方法的请求参数
RPC::LoginRequest request;
request.set_name("zhangsan");
request.set_pwd("123");
//rpc方法的响应
RPC::LoginResponse response;
//stub.Login()调用channel_->CallMethod(descriptor()->method(0),controller, request, response, done)发送request到服务器端,并填充response
MprpcController controller;
stub.Login(&controller, &request, &response, nullptr);
//读取一次rpc调用完成后的response
if (controller.Failed()) //RPC调用过程中出现错误了
{
std::cout << controller.ErrorText() << std::endl;
}
else
{
if (0 == response.result().errcode())
{
std::cout << "rpc Login response success : " << response.success() << std::endl;
}
else
{
std::cout << "rpc Login response error : " << response.result().errmsg() << std::endl;
}
}
//调用远程发布的rpc方法Register
RPC::RegisterRequest req;
req.set_id(2001);
req.set_name("linZY");
req.set_pwd("666666");
RPC::RegisterResponse rsp;
//以同步的方式发起rpc调用请求,等待返回结果
MprpcController controller1;
stub.Register(&controller1, &req, &rsp, nullptr);
//一次rpc调用完成,读调用的结果
if (controller1.Failed()) //RPC调用过程中出现错误了
{
std::cout << controller1.ErrorText() << std::endl;
}
else
{
if (0 == rsp.result().errcode())
{
std::cout << "rpc register response success:" << rsp.success() << std::endl;
}
else
{
std::cout << "rpc register response error : " << rsp.result().errmsg() << std::endl;
}
}
return 0;
}