C++实现简单的RPC框架

简介

     RPC是远程过程调用(Remote Procedure Call)的缩写形式 ,RPC的目的是为了简化网络通信,让用户可以专注于业务处理,不用关心网络层的处理,真正实现在客户端A中调用函数F就可以调用服务端B中的函数F的目的。

     RPC 模型引入存根进程( stub) 的概念, 对于服务端的服务类A,在客户端通过A::stub类进行调用,中间的网络交互流程有RPC框架进行实现。

实现

    我们可以借助protobuf来实现序列化和stub的生成,借助HpSocket来完成网络的交互,为了简单,我们采用HTTP协议来进行消息的交互。

    protobuf生成stub

        

RPC交互流程

    

实现流程

第一步、定义protobuf结构

1syntax = "proto3"; 2 3//支持rpc服务代码生成 4option cc_generic_services = true; 5 6//C#命名空间 7option csharp_namespace = "Google.Protobuf.Auth"; 8 9package Auth; 10 11 12//Rpc协议 13message RpcProtocol 14{ 15uint32 serviceId = 1; 16uint32 methodId = 2; 17bytes data = 3; 18int32 falg = 4; 19} 20 21 22message UserInfo 23{ 24 string phoneNum = 1; 25 string password = 2; 26} 27 28message ResponseMsg 29{ 30 int32 code = 1; 31 bytes message = 2; 32} 33 34//鉴权服务 35service Authentication { 36 //注册申请 37 rpc UserApplyReg(UserInfo) returns (ResponseMsg); 38 //用户注册 39 rpc UserRegister(UserInfo) returns (ResponseMsg); 40 //用户登陆 41 rpc UserLogin(UserInfo) returns (ResponseMsg); 42}

第二步、服务端实现

1#include <stdio.h> 2#include "WebService.h" 3#include "Authentication.h" 4//Rcp 服务端演示 5int main() 6{ 7 //启动web接口线程 8 WebService *pSrvProc = new WebService(); 9 pSrvProc->RegisterService(new CAuthentication); 10 11 CHttpServerPtr pHttpSrv(pSrvProc); 12 13 if (pHttpSrv->Start("0.0.0.0", 9090)) 14 { 15 printf("创建web server 成功"); 16 } 17 else 18 { 19 printf("创建web server 失败"); 20 } 21 22 while (true) 23 { 24 Sleep(10000); 25 } 26}

第三步、客户端实现

1#include <iostream> 2#include "RpcChannel.h" 3#include "RpcController.h" 4#include "proto\Authentication.pb.h" 5//Rcp 客户端演示 6int main() 7{ 8 std::string strSrvAddr = "http://127.0.0.1:9090"; 9 CRpcChannel channel(strSrvAddr); 10 11 CRpcController pController; 12 Auth::Authentication::Stub stub(&channel); 13 Auth::UserInfo req; 14 Auth::ResponseMsg res; 15 16 req.set_phonenum("10086"); 17 stub.UserApplyReg(&pController, &req, &res, NULL); 18 std::cout << res.message() << std::endl; 19 20 req.set_password("********"); 21 stub.UserRegister(&pController, &req, &res, NULL); 22 std::cout << res.message() << std::endl; 23 24 stub.UserLogin(&pController, &req, &res, NULL); 25 std::cout << res.message() << std::endl; 26}

核心代码

一、CRpcChannel 的实现,用于封装客户端与服务端交互流程

1#include "RpcChannel.h" 2#include "proto\Authentication.pb.h" 3#include <google\protobuf\message_lite.h> 4#include <google\protobuf\message.h> 5 6#define PROTOBUF_PROTOCOL_FLAG 0xfafbfcfd 7 8CRpcChannel::CRpcChannel(const std::string& srvAddr):m_strSrvAddr(srvAddr) 9{ 10} 11 12CRpcChannel::~CRpcChannel() 13{ 14} 15 16void CRpcChannel::CallMethod(const proto::MethodDescriptor* method, 17 proto::RpcController* controller, 18 const proto::Message* request, 19 proto::Message* response, 20 proto::Closure* done) 21{ 22 Auth::RpcProtocol message; 23 message.set_serviceid(method->service()->index()); 24 message.set_methodid(method->index()); 25 message.set_falg(PROTOBUF_PROTOCOL_FLAG); 26 message.set_data(request->SerializeAsString()); 27 28 CHttpSyncClientPtr httpReq(nullptr); 29 std::string strBody = message.SerializeAsString(); 30 int nSize = strBody.size(); 31 std::string strBodySize = std::to_string(nSize); 32 33 THeader header[] = { { "Content-Type", "text/plain;charset=utf-8" },{ "Content-Length", strBodySize.c_str() } }; 34 35 int iHeaderCount = sizeof(header) / sizeof(THeader); 36 37 if (!httpReq->OpenUrl("GET", m_strSrvAddr.c_str(), header, iHeaderCount, (const BYTE*)strBody.c_str(), strBody.size())) 38 { 39 printf("发送结果失败"); 40 return; 41 } 42 43 BYTE * respBody = nullptr; 44 int len = 0; 45 if (httpReq->GetResponseBody((LPCBYTE*)&respBody, &len) == FALSE) 46 return; 47 48 response->ParseFromString((char*)respBody); 49}

二、服务器处理

1EnHttpParseResult WebService::OnMessageComplete(IHttpServer * pSender, CONNID dwConnID) 2{ 3 char* pszBuf = nullptr; 4 pSender->GetConnectionExtra(dwConnID, (VOID**)&pszBuf); 5 6 char szBuf[64] = { 0 }; 7 int nSize = sizeof(szBuf); 8 USHORT nPort; 9 pSender->GetRemoteAddress(dwConnID, szBuf, nSize, nPort); 10 11 Auth::RpcProtocol protoMsg; 12 if (!protoMsg.ParseFromString(pszBuf)) 13 { 14 std::cout << "无效消息" << std::endl; 15 return HPR_ERROR; 16 } 17 18 if (m_mapService.find(protoMsg.serviceid()) != m_mapService.end()) 19 { 20 auto pRpcMonitor = m_mapService[protoMsg.serviceid()]; 21 const protoBuf::ServiceDescriptor *service_descriptor = pRpcMonitor->GetDescriptor(); 22 23 24 const protoBuf::MethodDescriptor *method_descriptor = service_descriptor->method(protoMsg.methodid()); 25 const protoBuf::Message& request_proto = pRpcMonitor->GetRequestPrototype(method_descriptor); 26 const protoBuf::Message& response_proto = pRpcMonitor->GetResponsePrototype(method_descriptor); 27 28 protoBuf::Message *reqMsg = request_proto.New(); 29 reqMsg->ParseFromString(protoMsg.data()); 30 protoBuf::Message *resMsg = response_proto.New(); 31 CRpcController pController(szBuf); 32 pRpcMonitor->CallMethod(method_descriptor, &pController, reqMsg, resMsg, NULL); 33 34 std::string strBody = resMsg->SerializeAsString(); 35 int nSize = strBody.size(); 36 std::string strBodySize = std::to_string(nSize); 37 THeader header[] = { { "Content-Type", "text/plain;charset=utf-8" },{ "Content-Length", strBodySize.c_str() } }; 38 39 int iHeaderCount = sizeof(header) / sizeof(THeader); 40 pSender->SendResponse(dwConnID, 41 HSC_OK, 42 "Http Server OK", 43 header, iHeaderCount, 44 (const BYTE*)strBody.c_str(), 45 strBody.size()); 46 } 47 return HPR_OK; 48}

三、服务端业务实现

1#include "Authentication.h" 2 3void CAuthentication::UserApplyReg(::google::protobuf::RpcController * controller, const::Auth::UserInfo * request, ::Auth::ResponseMsg * response, ::google::protobuf::Closure * done) 4{ 5 std::cout << "用户:" << request->phonenum() << "申请" << std::endl; 6 response->set_code(0); 7 response->set_message("允许申请"); 8} 9 10void CAuthentication::UserRegister(::google::protobuf::RpcController * controller, const::Auth::UserInfo * request, ::Auth::ResponseMsg * response, ::google::protobuf::Closure * done) 11{ 12 std::cout << "用户:" << request->phonenum() << ", 密码 " << request->password() << "正在注册" << std::endl; 13 response->set_code(0); 14 response->set_message("注册成功"); 15} 16 17void CAuthentication::UserLogin(::google::protobuf::RpcController * controller, const::Auth::UserInfo * request, ::Auth::ResponseMsg * response, ::google::protobuf::Closure * done) 18{ 19 std::cout << "用户:" << request->phonenum() << ", 密码 " << request->password() << "正在登陆" << std::endl; 20 response->set_code(0); 21 response->set_message("登陆成功"); 22}

至此一个简单的RPC交互流程就完成了

源码地址:https://gitee.com/lingluonianhua/EasyRpc.git

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

swap空间的增减方法

(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )