服务端流程
定义server的选项参数
主要方法是定义RpcServerOptions
对象,在给对象中,我们可以对服务端进行基础配置,该RpcServerOptions
类主要的参数有:
//配置线程数量
sofa::pbrpc::RpcServerOptions options;
options.work_thread_num = 4; //工作线程数为4
定义服务器控制对象
主要方法是实例化RpcServer
对象,该类的主要方法有:
- Start
- Stop
- Run
该类实例化的对象需要使用RpcServerOptions
的对象进行初始化,因为RpcServer
类中包含一个RpcServerOptions
的参数,我们可以理解为RpcServer
按照RpcServerOptions
规定的配置进行操作。
sofa::pbrpc::RpcServerOptions options;
...对options进行配置
sofa::pbrpc::RpcServer rpc_server(options);
开始server服务
开始服务的方式非常简单,就是调用Start函数即可,在Start函数中,需要传递的参数为服务器的Ip以及端口。
我们在使用该函数的时候,只需要将地址信息按照字符串的形式传递即可,主要的格式为ip:port
,该函数的返回值类型为bool类型,因此,我们可以通过返回值判断其是否执行成功。
if(rpc_server.Start("0.0.0.0:3000"))
{
cout<<"Start Server success"<<endl;
}
else
{
cout<<"Start Server failed"<<endl;
}
注册server服务
注册服务简单理解就是我们服务器的功能逻辑,一般是需要我们自己进行编写该类,同时该类需要继承sofa::pbrpc::test::EchoServer
,我们可以将sofa::pbrpc::test::EchoServer
类理解为一个接口类,该类中的Echo函数需要我们进行重写,因为该函数为服务器逻辑处理函数,是一个纯虚函数。
//本次服务器主要的功能为实现两个数的相加,request、response是一个格式为protobuf的消息类
class TestEcho_Server():public sofa::pbrpc::test::EchoServer //继承对应的处理类
{
public:
TestEcho_Server();
~TestEho_Server();
private:
vritual void Echo(google::protobuf::RpcController* controller ,
const sofa:pbrpc::test::EchoRequest* request,
sofa::pbrpc::test::EchoResponse* response,
google::protobuf::Closure* done)
{
sofa::pbrpc::RpcController* cntl = static_cast<sofa::pbrpc::RpcController*>(controller);
//获取请求消息
int val1 = request->val1();
int val2 = request->val2();
int sum = val1 + val2;
//设置响应消息
response->set_sum(sum);
done->Run();
}
};
int main()
{
//注册操作,定义执行方式
sofa::pbrpc::test::EchoServer* echo_server = new TestEcho_Server();
if(rpc_server.RegisterService(echo_server))
{
cout<<"Register Server success"<<endl;
}
}
开始服务
rpc_server.Run()
结束服务
rpc_server.Stop();
同步客户端流程
定义客户端对象
实现方式为sofa::pbrpc::RpcClientOptions
对象,通过该对象我们可以对客户端程序进行一些基本的配置,例如线程数。
sofa::pbrpc::RpcClientOptions client_options;
client_options.work_thread_num = 8;
sofa::pbrpc::RpcClient rpc_client(client_options);
该对象的主要功能是标示一个通道。
定义一个通道channel
定义RpcChannel对象,代表一个消息通道,需传入Server端服务地址。
sofa::pbrpc::RpcChannel rpc_channel(&rpc_client, "127.0.0.1:3000");
定义请求与回复消息对象
在请求消息的时候,我们可以对其进行赋值操作。
sofa::pbrpc::test::EchoRequest request;
request.val1(1);
request.val2(1);
sofa::pbrpc::test::EchoResponse response;
response对象会在服务端对其进行赋值,因此在访问结束后,我们只需要根据response获取对应的消息。
定义连接控制器
在连接控制器中,我们可以对本次连接进行一些基本的设置,例如:超时等待时间,压缩方式等。
sofa::pbrpc::RpcController controller;
controller.SetTimeout(3000);
与服务器建立连接
在与服务器建立连接的时候,我们只需要实例化一个EchoServer_Stub对象即可,该对象构造函数所需要的参数为channel通道。
sofa::pbrpc::test::EchoServer_Stub stub(&rpc_channel);
发起调用
在发起调用中,主要方法就是调用Echo函数,具体的参数为:连接控制器,请求消息,回应消息,调用方式,如果调用方式为NULL,则表示同步调用。在调用结束后,可以通过连接控制器,判断本次的调用是否成功。
stub.Echo(&controller, &request, &response, NULL);
if(!controller.Failed())
{
cout<<"调用成功"<<endl;
}
异步客户端流程
异步客户端流程与同步客户端的流程主要区别就是多了一个回调函数,同时在执行Echo的时候,传入毁掉函数即可。
本次模拟一台客户端请求100000条消息,同步处理的时间基本上为30秒左右,异步处理时间为3秒左右。100000次请求基本上不会丢失。
//服务器代码
#include <sofa/pbrpc/pbrpc.h>
#include<signal.h>
#include "echo_service.pb.h"
#include<iostream>
class EchoServerFunc:public sofa::pbrpc::test::EchoServer
{
public:
EchoServerFunc(){
}
virtual ~EchoServerFunc(){
}
private:
virtual void Echo(google::protobuf::RpcController* _cntl,
const sofa::pbrpc::test::EchoRequest* request,
sofa::pbrpc::test::EchoResponse* response,
google::protobuf::Closure* done)
{
sofa::pbrpc::RpcController* cntl = static_cast<sofa::pbrpc::RpcController*>(_cntl);
int number1,number2;
int sum;
number1 = request->number1();
number2 = request->number2();
sum = number1 + number2;
//SLOG(NOTICE, "Echo(): request address is %s: number1 = %d: number2 = %d:",cntl->RemoteAddress().c_str(), request->number1(),request->number2());
response->set_sum(sum);
done->Run();
}
};
int main()
{
SOFA_PBRPC_SET_LOG_LEVEL(NOTICE);
sofa::pbrpc::RpcServerOptions server_options;
int work_thread_num,io_service_pool_size;
std::cout<<"请输入work_thread_num与io_service_pool_size的值"<<std::endl;
std::cin>>work_thread_num>>io_service_pool_size;
server_options.work_thread_num = work_thread_num;
server_options.io_service_pool_size = io_service_pool_size;
sofa::pbrpc::RpcServer rpc_server(server_options);
if(!rpc_server.Start("0.0.0.0:12321"))
{
SLOG(ERROR,"rpc_server start failed");
return EXIT_FAILURE;
}
sofa::pbrpc::test::EchoServer* echo_server = new EchoServerFunc();
if(!rpc_server.RegisterService(echo_server))
{
SLOG(ERROR,"register Service failed");
return EXIT_FAILURE;
}
rpc_server.Run();
rpc_server.Stop();
return EXIT_SUCCESS;
}
#include <sofa/pbrpc/pbrpc.h>
#include "echo_service.pb.h"
#include<iostream>
#include<time.h>
using namespace std;
sofa::pbrpc::RpcClientOptions client_options;
int main()
{
SOFA_PBRPC_SET_LOG_LEVEL(NOTICE);
sofa::pbrpc::RpcChannelOptions channel_options;
int work_thread_num,callback_thread_num;
std::cout<<"请输入work_thread_num的值与callback_pthread_num的值"<<std::endl;
std::cin>>work_thread_num>>callback_thread_num;
client_options.work_thread_num = work_thread_num;
client_options.callback_thread_num = callback_thread_num;
sofa::pbrpc::RpcClient rpc_client(client_options);
sofa::pbrpc::RpcChannel rpc_channel(&rpc_client,"127.0.0.1:12321",channel_options);
sofa::pbrpc::RpcController* cntl = new sofa::pbrpc::RpcController();
sofa::pbrpc::test::EchoRequest* request = new sofa::pbrpc::test::EchoRequest();
sofa::pbrpc::test::EchoResponse* response = new sofa::pbrpc::test::EchoResponse();
sofa::pbrpc::test::EchoServer_Stub* stub = new sofa::pbrpc::test::EchoServer_Stub(&rpc_channel);
int i = 100000;
int successCount = 0;
struct timeval tv1,tv2;
gettimeofday(&tv1,NULL);
while(i>0)
{
i--;
cntl->Reset();
cntl->SetTimeout(2000);
int number1,number2;
//std::cin>>number1>>number2;
number1 = i;
number2 = i-1;
request->set_number1(number1);
request->set_number2(number2);
stub->Echo(cntl,request,response,NULL);
if(!cntl->Failed())
{
//SLOG(NOTICE,"response message %d",response->sum());
successCount++;
}
else
{
//SLOG(ERROR,"request failed %s:",cntl->ErrorText().c_str());
}
}
std::cout<<"成功数:"<<successCount<<endl;
gettimeofday(&tv2,NULL);
cout<<"运行时间:"<<tv2.tv_sec*1000+tv2.tv_usec/1000 - tv1.tv_sec*1000-tv1.tv_usec/1000<<endl;
delete cntl;
delete request;
delete response;
delete stub;
return EXIT_SUCCESS;
}
//异步客户端代码
#include<sofa/pbrpc/pbrpc.h>
#include"echo_service.pb.h"
#include<unistd.h>
#include<pthread.h>
#include<time.h>
#include<iostream>
int sum = 0;
pthread_mutex_t mutex1;
pthread_mutex_t mutex2;
static int failedCount = 0;
static int successCount = 0;
void EchoCallback(sofa::pbrpc::RpcController* controller,
sofa::pbrpc::test::EchoRequest* request,
sofa::pbrpc::test::EchoResponse* response
)
{
if(controller->Failed())
{
//SLOG(ERROR,"rpc client failed");
pthread_mutex_lock(&mutex1);
failedCount++;
pthread_mutex_unlock(&mutex1);
}
else
{
pthread_mutex_lock(&mutex1);
successCount++;
pthread_mutex_unlock(&mutex1);
//SLOG(NOTICE,"%d + %d = %d",request->number1(),request->number2(),response->sum());
}
pthread_mutex_lock(&mutex2);
sum ++;
pthread_mutex_unlock(&mutex2);
}
int main()
{
pthread_mutex_init(&mutex1,NULL);
pthread_mutex_init(&mutex2,NULL);
SOFA_PBRPC_SET_LOG_LEVEL(NOTICE);
sofa::pbrpc::RpcClientOptions client_options;
int work_thread_num = 8;
int callback_thread_num = 8;
//std::cout<<"请输入work_thread_num与callback_thread_num的个数";
//std::cin>>work_thread_num>>callback_thread_num;
client_options.work_thread_num = work_thread_num;
client_options.callback_thread_num = callback_thread_num;
sofa::pbrpc::RpcClient rpc_client(client_options);
sofa::pbrpc::RpcChannelOptions channel_options;
sofa::pbrpc::RpcChannel rpc_channel(&rpc_client,"127.0.0.1:12321",channel_options);
sofa::pbrpc::test::EchoRequest request;
sofa::pbrpc::test::EchoResponse response;
sofa::pbrpc::test::EchoServer_Stub stub(&rpc_channel);
struct timeval tv1,tv2;
gettimeofday(&tv1,NULL);
int count = 200000;
while(count > 0)
{
sofa::pbrpc::RpcController controller;
request.set_number1(1);
request.set_number2(1);
controller.Reset();
controller.SetTimeout(10000);
google::protobuf::Closure* done = sofa::pbrpc::NewClosure(&EchoCallback, &controller,&request, &response);
stub.Echo(&controller,&request,&response,done);
count--;
}
while(sum<200000)
{
usleep(20000);
}
gettimeofday(&tv2,NULL);
std::cout<<"程序运行时间为:"<<tv2.tv_sec*1000+tv2.tv_usec/1000 - tv1.tv_sec*1000-tv1.tv_usec/1000<<std::endl;
std::cout<<"成功次数:"<<successCount<<std::endl;
std::cout<<"失败次数:"<<failedCount<<std::endl;
return EXIT_SUCCESS;
}
以下数据是在本机测出来的,不同的配置可能会出现不同的结果。
多个异步客户端测的数据。