C++实现简单的RPC框架

简介ios

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

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

实现服务器

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

    protobuf生成stub框架

        

RPC交互流程函数

    

实现流程ui

第一步、定义protobuf结构google

syntax = "proto3";

//支持rpc服务代码生成
option cc_generic_services = true;

//C#命名空间
option csharp_namespace = "Google.Protobuf.Auth";

package Auth;


//Rpc协议
message RpcProtocol
{
uint32 serviceId = 1;
uint32 methodId = 2;
bytes data = 3;
int32 falg = 4;
}


message UserInfo
{
    string phoneNum = 1;
	string password = 2;
}

message ResponseMsg
{
	int32 code = 1;
    bytes message = 2;
}

//鉴权服务
service Authentication {
  //注册申请
  rpc UserApplyReg(UserInfo) returns (ResponseMsg);
  //用户注册
  rpc  UserRegister(UserInfo) returns (ResponseMsg);
  //用户登录
  rpc  UserLogin(UserInfo) returns (ResponseMsg);
}

第二步、服务端实现spa

#include <stdio.h>
#include "WebService.h"
#include "Authentication.h"
//Rcp 服务端演示
int main()
{
	//启动web接口线程
	WebService  *pSrvProc = new WebService();
	pSrvProc->RegisterService(new CAuthentication);

	CHttpServerPtr pHttpSrv(pSrvProc);
	
	if (pHttpSrv->Start("0.0.0.0", 9090))
	{
		printf("建立web server 成功");
	}
	else
	{
		printf("建立web server 失败");
	}

	while (true)
	{
		Sleep(10000);
	}
}

第三步、客户端实现

#include <iostream>
#include "RpcChannel.h"
#include "RpcController.h"
#include "proto\Authentication.pb.h"
//Rcp 客户端演示
int main()
{
	std::string strSrvAddr = "http://127.0.0.1:9090";
	CRpcChannel channel(strSrvAddr);

	CRpcController pController;
	Auth::Authentication::Stub stub(&channel);
	Auth::UserInfo req;
	Auth::ResponseMsg res;

	req.set_phonenum("10086");
	stub.UserApplyReg(&pController, &req, &res, NULL);
	std::cout << res.message() << std::endl;

	req.set_password("********");
	stub.UserRegister(&pController, &req, &res, NULL);
	std::cout << res.message() << std::endl;

	stub.UserLogin(&pController, &req, &res, NULL);
	std::cout << res.message() << std::endl;
}

核心代码

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

#include "RpcChannel.h"
#include "proto\Authentication.pb.h"
#include <google\protobuf\message_lite.h>
#include <google\protobuf\message.h>

#define PROTOBUF_PROTOCOL_FLAG 0xfafbfcfd

CRpcChannel::CRpcChannel(const std::string& srvAddr):m_strSrvAddr(srvAddr)
{
}

CRpcChannel::~CRpcChannel()
{
}

void CRpcChannel::CallMethod(const proto::MethodDescriptor* method,
	proto::RpcController* controller,
	const proto::Message* request,
	proto::Message* response,
	proto::Closure* done)
{
	Auth::RpcProtocol message;
	message.set_serviceid(method->service()->index());
	message.set_methodid(method->index());
	message.set_falg(PROTOBUF_PROTOCOL_FLAG);
	message.set_data(request->SerializeAsString());

	CHttpSyncClientPtr httpReq(nullptr);
	std::string strBody = message.SerializeAsString();
	int nSize = strBody.size();
	std::string strBodySize = std::to_string(nSize);

	THeader header[] = { { "Content-Type", "text/plain;charset=utf-8" },{ "Content-Length", strBodySize.c_str() } };

	int iHeaderCount = sizeof(header) / sizeof(THeader);
 
	if (!httpReq->OpenUrl("GET", m_strSrvAddr.c_str(), header, iHeaderCount, (const BYTE*)strBody.c_str(), strBody.size()))
	{
		printf("发送结果失败");
		return;
	}
	
	BYTE * respBody = nullptr;
	int len = 0;
	if (httpReq->GetResponseBody((LPCBYTE*)&respBody, &len) == FALSE)
		return;

	response->ParseFromString((char*)respBody);
}

2、服务器处理

EnHttpParseResult WebService::OnMessageComplete(IHttpServer * pSender, CONNID dwConnID)
{
	char* pszBuf = nullptr;
	pSender->GetConnectionExtra(dwConnID, (VOID**)&pszBuf);

	char szBuf[64] = { 0 };
	int nSize = sizeof(szBuf);
	USHORT nPort;
	pSender->GetRemoteAddress(dwConnID, szBuf, nSize, nPort);

	Auth::RpcProtocol protoMsg;
	if (!protoMsg.ParseFromString(pszBuf))
	{
		std::cout << "无效消息" << std::endl;
		return HPR_ERROR;
	}
	
	if (m_mapService.find(protoMsg.serviceid()) != m_mapService.end())
	{
		auto pRpcMonitor = m_mapService[protoMsg.serviceid()];
		const protoBuf::ServiceDescriptor *service_descriptor = pRpcMonitor->GetDescriptor();


		const protoBuf::MethodDescriptor *method_descriptor = service_descriptor->method(protoMsg.methodid());
		const protoBuf::Message& request_proto = pRpcMonitor->GetRequestPrototype(method_descriptor);
		const protoBuf::Message& response_proto = pRpcMonitor->GetResponsePrototype(method_descriptor);

		protoBuf::Message *reqMsg = request_proto.New();
		reqMsg->ParseFromString(protoMsg.data());
		protoBuf::Message *resMsg = response_proto.New();
		CRpcController pController(szBuf);
		pRpcMonitor->CallMethod(method_descriptor, &pController, reqMsg, resMsg, NULL);

		std::string strBody = resMsg->SerializeAsString();
		int nSize = strBody.size();
		std::string strBodySize = std::to_string(nSize);
		THeader header[] = { { "Content-Type", "text/plain;charset=utf-8" },{ "Content-Length", strBodySize.c_str() } };
		
		int iHeaderCount = sizeof(header) / sizeof(THeader);
		pSender->SendResponse(dwConnID,
			HSC_OK,
			"Http Server OK",
			header, iHeaderCount,
			(const BYTE*)strBody.c_str(),
			strBody.size());
	}
	return HPR_OK;
}

3、服务端业务实现

#include "Authentication.h"

void CAuthentication::UserApplyReg(::google::protobuf::RpcController * controller, const::Auth::UserInfo * request, ::Auth::ResponseMsg * response, ::google::protobuf::Closure * done)
{
	std::cout << "用户:" << request->phonenum() << "申请" << std::endl;
	response->set_code(0);
	response->set_message("容许申请");
}

void CAuthentication::UserRegister(::google::protobuf::RpcController * controller, const::Auth::UserInfo * request, ::Auth::ResponseMsg * response, ::google::protobuf::Closure * done)
{
	std::cout << "用户:" << request->phonenum() << ", 密码 " << request->password() << "正在注册" << std::endl;
	response->set_code(0);
	response->set_message("注册成功");
}

void CAuthentication::UserLogin(::google::protobuf::RpcController * controller, const::Auth::UserInfo * request, ::Auth::ResponseMsg * response, ::google::protobuf::Closure * done)
{
	std::cout << "用户:" << request->phonenum() << ", 密码 " << request->password() << "正在登录" << std::endl;
	response->set_code(0);
	response->set_message("登录成功");
}

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

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

相关文章
相关标签/搜索