一、实现目标

这里实现的就是左边黑圈里的过程:
开始调用->序列化->发送->接收响应结果->反序列化

右边的_stub是专门给rpc服务调用者来使用的,想要调用rpc服务,也应该用在user.proto定义好的
- 定义了一个名为 Login 的远程过程调用方法
- 输入参数:LoginRequest - 包含登录请求信息
- 返回值:LoginResponse - 包含登录响应结果
cpp
service UserServiceRpc{
// Login handles user authentication with name and password
rpc Login(LoginRequest) returns(LoginResponse);
}
二、caller下calluserservice.cc实现
cpp
#include<iostream>
#include "user.pb.h"
#include"mprpcapplication.h"
#include"mprpcchannel.h"
int main(int argc,char **argv){
//整个程序启动后,想用mprpc框架调用rpc服务,一定要先调用框架的初始化函数(只初始化一次)
MprpcApplication::Init(argc,argv);
//演示远程调用发布的rpc方法 Login
fixbug::UserServiceRpc_Stub stub(new MprpcChannel());
//stub.Login();
//rpc方法的请求参数
fixbug::LoginRequest request;
request.set_name("zhang san");
request.set_password("123456");
//RPC方法的响应
fixbug::LoginResponse response;
//发起rpc方法的调用 同步的rpc调用过程 MprpcChannel::callmethod
stub.Login(nullptr, &request, &response, nullptr);
//一次rpc调用完整,读取调用结果
//0表示成功,非0表示错误 如404,not found
if(response.result().errcode() == 0){
std::cout<<"rpc login resonse success: "<<response.success()<<std::endl;
}else{
std::cout<<"rpc login resonse failed: "<<response.result().errcode()<<" msg: "<<response.result().errmsg()<<std::endl;
}
return 0;
}
1、要先初始化整个rpc框架
cpp
MprpcApplication::Init(argc,argv);
- 初始化RPC应用程序
- 解析命令行参数获取配置文件路径
- 加载配置文件中的服务器IP、端口等配置信息
2、调用
cpp
//演示远程调用发布的rpc方法 Login
fixbug::UserServiceRpc_Stub stub(new MprpcChannel());
//stub.Login();
//rpc方法的请求参数
fixbug::LoginRequest request;
request.set_name("zhang san");
request.set_password("123456");
//RPC方法的响应
fixbug::LoginResponse response;
//发起rpc方法的调用 同步的rpc调用过程 MprpcChannel::callmethod
stub.Login(nullptr, &request, &response, nullptr);
-
fixbug::UserServiceRpc_Stub就像是外卖平台的客户端APP -
stub就是你手机上打开的外卖APP -
MprpcChannel()就像是你的手机网络(4G/5G/WiFi)
最上面就是"打开外卖APP,连接到网络",最下面就是下单点餐。
3、获取响应结果
cpp
//一次rpc调用完整,读取调用结果
//0表示成功,非0表示错误 如404,not found
if(response.result().errcode() == 0){
std::cout<<"rpc login resonse success: "<<response.success()<<std::endl;
}else{
std::cout<<"rpc login resonse failed: "<<response.result().errcode()<<" msg: "<<response.result().errmsg()<<std::endl;
}
三、mprpcchannel.h
cpp
#pragma once
#include<google/protobuf/service.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
class MprpcChannel:public google::protobuf::RpcChannel{
public:
void CallMethod(const google::protobuf::MethodDescriptor* method,
google::protobuf::RpcController* controller,
const google::protobuf::Message* request,
google::protobuf::Message* response,
google::protobuf::Closure* done
);
};
这里定义一个MprpcChannel类,继承google::protobuf::RpcChannel类,实现该虚函数

不管调用什么方法如这里stub.Login(),都会转换为对callmethod这一个方法调用
比如这里第一个参数就是Login
四、mprpcchannel.cc
该函数实现
1、先获取所有
2、将请求的rpc参数组装 数组的序列化(进行序列化后依然是string类型,cout遇到可打印的ASCLL字符就打印 )
3、发送rpc请求 wait
4、接收rpc响应 反序列化
先上完整代码
cpp
#include "mprpcchannel.h"
#include <string>
#include "rpcheader.pb.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <error.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "mprpcapplication.h"
#include <unistd.h>
/*
rpc请求的数组组装 数组的序列化
发送rpc请求 wait
接收rpc响应 反序列化
*/
void MprpcChannel::CallMethod(const google::protobuf::MethodDescriptor* method,
google::protobuf::RpcController* controller,
const google::protobuf::Message* request,
google::protobuf::Message* response,
google::protobuf::Closure* done){
//header_size +service_name + method_name + args_size + args_str
const google::protobuf::ServiceDescriptor* sd = method->service();
std::string service_name = sd->name();
std::string method_name = method->name();
//获取参数的序列化字符串长度 args_size
int args_size = 0;
std::string args_str;
if(!request->SerializeToString(&args_str)){
std::cout<<"serialize request failed"<<args_str<<std::endl;
return;
}else{
args_size = args_str.size();
}
//定义rpc的请求header
mprpc::RpcHeader rpcHeader;
rpcHeader.set_service_name(service_name);
rpcHeader.set_method_name(method_name);
rpcHeader.set_args_size(args_size);
//将header序列化
uint32_t header_size = 0;
std::string rpc_header_str;
if(rpcHeader.SerializeToString(&rpc_header_str)){
header_size = rpc_header_str.size();
}else{
std::cout<<"serialize header failed"<<std::endl;
return;
}
//拼接发送的rpc请求字符串
std::string send_rpc_str;
send_rpc_str.insert(0,std::string((char *)&header_size,4));
send_rpc_str += rpc_header_str;
send_rpc_str += args_str;
//打印测试
std::cout<<"=============================="<<std::endl;
std::cout<<"rpc_header_str: "<<rpc_header_str<<std::endl;
std::cout<<"header_size: "<<header_size<<std::endl;
std::cout<<"service_name: "<<service_name<<std::endl;
std::cout<<"method_name: "<<method_name<<std::endl;
std::cout<<"args_str: "<<args_str<<std::endl;
std::cout<<"send_rpc_str: "<<send_rpc_str<<std::endl;
std::cout<<"=============================="<<std::endl;
//使用tcp编程完成rpc方法的远程调用
int clientfd = socket(AF_INET,SOCK_STREAM,0);
if(clientfd == -1){
std::cout<<"create socket failed"<<errno<<std::endl;
return;
}
//设置服务端的ip和port
struct sockaddr_in server_addr;
std::string ip = MprpcApplication::GetInstance().GetConfig().Load("rpcserverip");
uint16_t port = atoi(MprpcApplication::GetInstance().GetConfig().Load("rpcserverport").c_str());
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = inet_addr(ip.c_str());
//连接rpc服务节点
int ret = connect(clientfd,(struct sockaddr*)&server_addr,sizeof(server_addr));
if(ret == -1){
std::cout<<"connect failed"<<errno<<std::endl;
close(clientfd);
exit(EXIT_FAILURE);
}
//发送rpc请求
if(send(clientfd,send_rpc_str.c_str(),send_rpc_str.size(),0) == -1){
std::cout<<"send rpc request failed"<<errno<<std::endl;
return;
}
//接收rpc响应
char recv_buf[1024] = {0};
int recv_size = 0;
if((recv_size=recv(clientfd,recv_buf,1024,0)) == -1){
std::cout<<"recv rpc response failed"<<errno<<std::endl;
close(clientfd);
return;
}
//反序列化 在复制给response_str时,遇到\0就不复制了,
// std::string response_str(recv_buf,0,recv_size);
// if(!response->ParseFromString(response_str)){
if(!response->ParseFromArray(recv_buf,recv_size)){
std::cout<<"response parse error"<<errno<<std::endl;
close(clientfd);
return;
}
close(clientfd);
}
1、两边的协议
服务端(RpcProvider)解析逻辑 :[4字节header_size] + [rpc_header_str] + [args_str] 解析,且从 rpc_header_str 里的 RpcHeader 对象取 args_size 来读 args_str。
所以客户端也应该按照这个格式发送。
二、拼接、发送
cpp
//拼接发送的rpc请求字符串
std::string send_rpc_str;
send_rpc_str.insert(0,std::string((char *)&header_size,4));
send_rpc_str += rpc_header_str;
send_rpc_str += args_str;
这里拼接的都是序列化后的
cpp
//发送rpc请求
if(send(clientfd,send_rpc_str.c_str(),send_rpc_str.size(),0) == -1){
std::cout<<"send rpc request failed"<<errno<<std::endl;
return;
}
这里使用.ctr()是因为
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
buf参数需要const void*(或const char*)- C语言API不接受C++的 std::string 对象
三、建立连接
cpp
//使用tcp编程完成rpc方法的远程调用
int clientfd = socket(AF_INET,SOCK_STREAM,0);
if(clientfd == -1){
std::cout<<"create socket failed"<<errno<<std::endl;
return;
}
//设置服务端的ip和port
struct sockaddr_in server_addr;
std::string ip = MprpcApplication::GetInstance().GetConfig().Load("rpcserverip");
uint16_t port = atoi(MprpcApplication::GetInstance().GetConfig().Load("rpcserverport").c_str());
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = inet_addr(ip.c_str());
//连接rpc服务节点
int ret = connect(clientfd,(struct sockaddr*)&server_addr,sizeof(server_addr));
if(ret == -1){
std::cout<<"connect failed"<<errno<<std::endl;
close(clientfd);
exit(EXIT_FAILURE);
}
先初始化好,然后用connect函数连接
四、接收响应
cpp
//接收rpc响应
char recv_buf[1024] = {0};
int recv_size = 0;
if((recv_size=recv(clientfd,recv_buf,1024,0)) == -1){
std::cout<<"recv rpc response failed"<<errno<<std::endl;
close(clientfd);
return;
}
//反序列化 在复制给response_str时,遇到\0就不复制了,
// std::string response_str(recv_buf,0,recv_size);
// if(!response->ParseFromString(response_str)){
if(!response->ParseFromArray(recv_buf,recv_size)){
std::cout<<"response parse error"<<errno<<std::endl;
close(clientfd);
return;
}
这里定义的recv_buf是数组,
通过注释里的方法,response_str只有\n,这是因为该构造函数希望以"\0"结尾

这样写也行
cpp
//反序列化 在复制给response_str时,遇到\0就不复制了,
std::string response_str(recv_buf,recv_size);
if(!response->ParseFromString(response_str)){
// if(!response->ParseFromArray(recv_buf,recv_size)){
std::cout<<"response parse error"<<errno<<std::endl;
close(clientfd);
return;
}
五、当前成果展示
