模拟生产环境使用thrift c++版
1. 简介
本文简单的模拟了实际生成环境场景中使用的C/S模型,使用thrift作为框架来进行开发,服务端实现了两个接口,使用ThreadPoolServer模型提供服务,由于只是学习thrift相关的使用,本文的代码不是很严谨,代码设计基本没有,请阅读本文之前最好有基本的thrift相关的知识。如
* thrift文件中的基本数据类型
* thrift文件中的简单的结构体定义
* 如何用thrift文件生成代码
2. thrift文件
在生成环境中,每次调用rpc都必须要有返回值,以标识rpc在业务层面的成功与否。
本次实验定义了一个通用返回结构体,由于thrift文件支持包含语法,所以将该结构体
定义在comm.thrift文件中,用于被其他thrift文件包含
comm.thrift:
struct ReturnMessage
{
1: i32 ret_code;
2: string ret_msg
}
业务接口和接口定义test.thrift文件:
include "comm.thrift"
namespace cpp xbshop.manage.login
struct ReqLoginService
{
1: string strUserName;
2: string strPassword;
}
//req+服务名定义的结构体代表该服务的请求参数,res+服务名定义的结构体代表该服务的返回参数
struct ResLoginService
{
1: comm.ReturnMessage stReturnMessage, //注意使用包含文件中定义的结构体时,需要加上文件名前缀,例如使用comm.thrfit文件中的结构体,需要加上comm.
2: bool logged
}
struct ReqQryOrderService
{
1: string order_no;
}
struct ResQryOrderService
{
1: comm.ReturnMessage stReturnMessage,
2: i64 total_fee;
}
//定义了两个服务,一个是LoginService登录服务,一个是QyrOrderService查询订单服务
service LoginService
{
comm.ReturnMessage login(1: ReqLoginService reqParams);
}
service QryOrderService
{
ResQryOrderService qryOrder(1: ReqQryOrderService reqParams);
}
使用命令thrift -r –gen cpp test.thrift , -r参数的含义是编译test.thrift文件的同时还会编译其包含文件comm.thrift
服务端代码
#include "LoginServiceHandle.h"
#include "QryOrderService.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TThreadPoolServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include "thrift/processor/TMultiplexedProcessor.h"
#include "thrift/server/TSimpleServer.h"
#include "concurrency/PosixThreadFactory.h"
#include "concurrency/ThreadManager.h"
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using namespace ::apache::thrift::concurrency;
using boost::shared_ptr;
using namespace ::xbshop::manage::login;
int main(int argc, char **argv) {
int port = 9090;
shared_ptr<LoginServiceHandler> handler(new LoginServiceHandler());
shared_ptr<QryOrderServiceHandler> spQryOrderServiceHandler(new QryOrderServiceHandler());
shared_ptr<TProcessor> spLoginProcessor(new LoginServiceProcessor(handler));
shared_ptr<TProcessor> spQryOrderServiceProcessor(new QryOrderServiceProcessor(spQryOrderServiceHandler));
shared_ptr<TServerTransport> serverTransport(new TServerSocket("127.0.0.1", port));
shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
shared_ptr<TMultiplexedProcessor> cMultiProcessor(new TMultiplexedProcessor());
cMultiProcessor->registerProcessor("LoginService", spLoginProcessor);
cMultiProcessor->registerProcessor("QryOrderService", spQryOrderServiceProcessor);
shared_ptr<ThreadManager> spThreadManager(ThreadManager::newSimpleThreadManager(10));
shared_ptr<ThreadFactory> spPthreadFactory(new PosixThreadFactory());
spThreadManager->threadFactory(spPthreadFactory);
spThreadManager->start();
TThreadPoolServer server(cMultiProcessor, serverTransport, transportFactory, protocolFactory, spThreadManager);
server.serve();
return 0;
}
如果服务端需要定义多个服务,需要使用TMultiplexedProcessor类注册多个processor。
如果要使用TThreadPoolServer服务模型,必须自己定义一个ThreadManager,并调用start函数,不然客户端调用rpc时会抛异常.服务端代码中的LoginServiceHandle.h和LoginServiceHandle.cpp是自己新建的,在生产环境中一个service的代码文件肯定是单独存放的,而自动生成的代码文件中handle与main函数是放在一起的
LoginServiceHandle.h
#ifndef _LOGIN_SERVICE_HANDLE_H
#define _LOGIN_SERVICE_HANDLE_H
#include "LoginService.h"
using namespace ::xbshop::manage::login;
class LoginServiceHandler : virtual public LoginServiceIf
{
public:
LoginServiceHandler();
void login(::ReturnMessage& _return, const ReqLoginService& reqParams);
};
#endif
LoginServiceHandle.cpp
#include "LoginServiceHandle.h"
LoginServiceHandler::LoginServiceHandler()
{
}
void LoginServiceHandler::login(::ReturnMessage& _return, const ReqLoginService& reqParams)
{
_return.ret_code = 0;
_return.ret_msg = "ok";
}
QryOrderService的实现
QryOrderServiceHandler::QryOrderServiceHandler()
{
}
void QryOrderServiceHandler::qryOrder(ResQryOrderService& _return, const ReqQryOrderService& reqParams)
{
if (reqParams.order_no == "123")
{
_return.stReturnMessage.ret_code = 0;
_return.stReturnMessage.ret_msg = "ok";
_return.total_fee = 100;
}
else
{
_return.stReturnMessage.ret_code = -1;
_return.stReturnMessage.ret_msg = "order_no error";
_return.total_fee = 0;
}
}
客户端代码
#include <stdio.h>
#include "LoginServiceHandle.h"
#include "QryOrderService.h"
#include "test_types.h"
#include "transport/TSocket.h"
#include "transport/TBufferTransports.h"
#include "protocol/TBinaryProtocol.h"
#include "protocol/TMultiplexedProtocol.h"
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using boost::shared_ptr;
using namespace ::xbshop::manage::login;
int main()
{
shared_ptr<TSocket> socket(new TSocket("127.0.0.1", 9090));
shared_ptr<TTransport> transport(new TBufferedTransport(socket));
shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
transport->open();
shared_ptr<TMultiplexedProtocol> cMp1(new TMultiplexedProtocol(protocol, "LoginService"));
shared_ptr<TMultiplexedProtocol> cMp2(new TMultiplexedProtocol(protocol, "QryOrderService"));
ReqQryOrderService stReqParams;
QryOrderServiceClient cQryOrderClient(cMp2);
ResQryOrderService stResParams;
stReqParams.order_no = "123";
cQryOrderClient.qryOrder(stResParams, stReqParams);
printf("%d %s\n", stResParams.stReturnMessage.ret_code, stResParams.stReturnMessage.ret_msg.c_str());
printf("%d\n", stResParams.total_fee);
transport->close();
return 0;
}
相应的客户端要使用多个service,需要用到TMultiplexedProtocol类,用来初始化相应service的客户端。