Thrift实践(C++)

news/2024/7/9 16:18:02 标签: c/c++, epoll

文章简介

运用Thrift的TNonblockingServer编写C++实践案例。

 

Thrift服务端编程

从Thrift-0.12.0版本的C++源代码来看服务端编程主要有:多线程模型,一个新的客户端连接创建一个线程处理;多线程线程池模型,将新的客户端连接放入任务队列中由线程池读取处理;事件驱动异步模型,注册监听事件和可读事件,将客户端的数据放入任务队列中由线程池进行处理。事件驱动异步模型更适合运用在互联网大量用户的场景中,也就是TNonblockingServer。

 

Thrift中TNonblockingServer的设计和实现

 

 

 

 

 

 

 

 

 

 

图1-1 TNonblockingServer的实现

如图1-1所示,当一个新的客户端连接accept时,会new一个TConnection对象,通过轮询选择算法发送给IOThread线程池,IOThread接收到客户端发来的请求数据时,将它打包成Task放入任务队列中,再由任务处理线程池Thread从任务队列pop出来调用服务端实现的业务逻辑函数处理。下面以用户注册的业务场景为例,实现一个具体的TNonblockingServer案例。

 

Thrift接口文件编写

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

//文件名称user.thrift

namespace cpp thrift.user

 

enum EUserType

{

QQ = 1,

WECHAT = 2

}

 

struct UserRegisterReq

{

1:required string sUserName;

2:required string sMd5Pwd;

3:string sPhoneNumber;

4:optional i32 iUserAge;

}

 

struct UserRegisterResp

{

1:required i32 iUserId;

2:required bool bSucc;

3:optional i32 iRetCode;

4:optional string sErrMsg;

}

 

service UserService{

UserRegisterResp UserRegister(1:EUserType eType, 2:UserRegisterReq oReq)

}

运行thrift -r --gen cpp user.thrift,生成服务端和客户端RPC接口文件。其中required是必传字段,optional是可选字段。

 

服务端代码实现

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

//文件名称nonsocketserver.cpp

#include <stdlib.h>

 

#include <iostream>

 

#include <thrift/protocol/TBinaryProtocol.h>

#include <thrift/transport/TNonblockingServerSocket.h>

#include <thrift/server/TNonblockingServer.h>

#include <thrift/concurrency/PlatformThreadFactory.h>

#include <thrift/concurrency/ThreadManager.h>

 

#include "gen-cpp/UserService.h"

 

namespace thrift

{

namespace user

{

class UserServiceHandler : virtual public UserServiceIf {

public:

UserServiceHandler() {}

virtual void UserRegister(UserRegisterResp& _return, const EUserType::type eType, const UserRegisterReq& oReq) {

std::cout << "etype=" << eType << " oReq=" << oReq << " oResp=" << _return << std::endl;

}

};

}//user

}//thrift

 

int main(int argc, char* argv[])

{

using namespace ::apache::thrift;

using namespace ::apache::thrift::concurrency;

using namespace ::apache::thrift::protocol;

using namespace ::apache::thrift::transport;

using namespace ::apache::thrift::server;

 

using namespace ::thrift::user;

 

int iIOThreadNum = 0, iTaskThreadNum = 0;

if (3 == argc) {

iIOThreadNum = ::strtol(argv[1], NULL, 10);

iTaskThreadNum = ::strtol(argv[2], NULL, 10);

}

 

int port = 9090;

//业务逻辑

stdcxx::shared_ptr<UserServiceHandler> testHandler(new UserServiceHandler());

//业务接口逻辑

stdcxx::shared_ptr<TProcessor> testProcessor(new UserServiceProcessor(testHandler));

//报文协议序列化 protocol

stdcxx::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactoryT<TBufferBase>());

 

//监听端口 transport

stdcxx::shared_ptr<TNonblockingServerTransport> nbSocket(new transport::TNonblockingServerSocket(port));

//创建非阻塞I/O服务 server

stdcxx::shared_ptr<TNonblockingServer> nonblockingServer(new TNonblockingServer(testProcessor, protocolFactory, nbSocket));

nonblockingServer->setNumIOThreads(iIOThreadNum); //多线程——连接处理

 

//建多线程任务处理

if (iTaskThreadNum > 0) {

stdcxx::shared_ptr<ThreadManager> pThreadManager = ThreadManager::newSimpleThreadManager(iTaskThreadNum);//多线程——任务处理

pThreadManager->threadFactory(stdcxx::shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory));

pThreadManager->start();

nonblockingServer->setThreadManager(pThreadManager);

}

 

//服务启动

nonblockingServer->serve();

//服务停止

nonblockingServer->stop();

 

return 0;

}

 

客户端代码实现

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

//文件名称client.cpp

#include <iostream>

 

#include <thrift/protocol/TBinaryProtocol.h>

#include <thrift/transport/TSocket.h>

#include <thrift/transport/TBufferTransports.h>

 

#include "gen-cpp/UserService.h"

 

int main(int argc, char **argv)

{

using namespace ::apache::thrift;

using namespace ::thrift::user;

 

//I/O transport

stdcxx::shared_ptr<transport::TSocket> socket(new transport::TSocket("127.0.0.1", 9090));

//数据读取方式 transport

stdcxx::shared_ptr<transport::TTransport> transport(new transport::TFramedTransport(socket));

//报文协议序列化 protocol

stdcxx::shared_ptr<protocol::TProtocol> protocol(new protocol::TBinaryProtocol(transport));

 

UserServiceClient client(protocol);

transport->open();

 

EUserType::type eType = EUserType::QQ;

UserRegisterReq oReq;

UserRegisterResp oResp;

client.UserRegister(oResp, eType, oReq);

 

transport->close();

 

std::cout << "eType=" << eType << " oReq=" << oReq << " oReps=" << oResp << std::endl;

 

return 0;

}

 

编译和运行

//编译服务端程序和客户端程序

g++ -c -o nonsocketserver.o nonsocketserver.cpp

g++ -c -o UserService.o gen-cpp/UserService.cpp

g++ -c -o user_types.o gen-cpp/user_types.cpp

g++ -g -Wall -o server nonsocketserver.o UserService.o user_types.o -lthrift -lthriftnb

g++ -c -o client.o client.cpp

g++ -g -Wall -o client client.o UserService.o user_types.o -lthrift -lthriftnb

 

//运行服务端

./server

Thrift: Mon Jan 28 00:01:38 2019 TNonblockingServer: Serving with 1 io threads.

Thrift: Mon Jan 28 00:01:38 2019 TNonblockingServer: using libevent 2.1.8-stable method epoll

Thrift: Mon Jan 28 00:01:38 2019 TNonblocking: IO thread #0 registered for listen.

Thrift: Mon Jan 28 00:01:38 2019 TNonblocking: IO thread #0 registered for notify.

Thrift: Mon Jan 28 00:01:38 2019 TNonblockingServer: IO thread #0 entering loop...

etype=QQ oReq=UserRegisterReq(sUserName=, sMd5Pwd=, sPhoneNumber=, iUserAge=<null>) oResp=UserRegisterResp(iUserId=0, bSucc=0, iRetCode=<null>, sErrMsg=<null>)

 

//运行客户端

./client

eType=QQ oReq=UserRegisterReq(sUserName=, sMd5Pwd=, sPhoneNumber=, iUserAge=<null>) oReps=UserRegisterResp(iUserId=0, bSucc=0, iRetCode=<null>, sErrMsg=<null>)

 

参考文献

[1] Mark Slee, Aditya Agarwal and Marc Kwiatkowski. Thrift: Scalable Cross-Language Services Implementation. 2007

[2] Apache Thrift官方网站, http://thrift.apache.org

[3] Apache Thrift源代码, https://github.com/apache/thrift

[4] Lex & Yacc 官方网站, http://dinosaur.compilertools.net

 

转载于:https://www.cnblogs.com/churen/p/10328526.html


http://www.niftyadmin.cn/n/1494787.html

相关文章

Jquery实现鼠标移动/移过到商品小图片上时替换掉大图片上的图片

query实现鼠标移动/移过到商品小图片上时替换掉大图片上的图片 1 . 实现效果 2 . 代码 <!doctype html> <html> <head><meta charset"utf-8"><title>图片变换</title><style>.show{width:330px; height:auto; margin:50p…

Mysql 安装服务无法启动解决方案与使用的一般使用指令

问题描述&#xff1a; 在安装mysql 时&#xff0c;如果第一次没安装成功&#xff0c;第二次重装可能出现莫名奇妙的情况。通过一番尝试&#xff0c;发现&#xff0c;安装往上的教程还是无法成功安装的主要原因是第一次安装虽然未成功&#xff0c;但是mysql 默认的3306端口已被占…

【百度地图一 - vue-baidu-map】vue结合vue-baidu-map实现百度地图

1. 效果 2. 使用 2.1 npm 安装 npm install vue-baidu-map --save2.2 ak申请 是在百度地图开发者平台申请的密钥 详见 百度地图开发者平台ak申请 2.3 main.js 引入 import BaiduMap from vue-baidu-map Vue.use(BaiduMap, {// ak 是在百度地图开发者平台申请的密钥 详见 h…

提升应用崩溃时的用户体验——去掉烦人的“很抱歉”提示框

相信很多在用或者用过Android系统的的手机的朋友都有过这样的经历&#xff1a;自己玩着玩着某个程序&#xff0c;突然屏幕一黑&#xff0c;然后出现一个对话框&#xff0c;提示很抱歉&#xff0c;应用程序已经停止工作。这意味着程序已然崩溃了&#xff0c;用户唯一要做的就是接…

【百度地图二 - vue-baidu-map】bm-marker和bm-info-window实现打点和点详情弹窗功能

1. 效果图 2. 实现代码&#xff1a; 2.1 template <bm-marker v-for"marker of markers" :position"{lng: marker.lng, lat: marker.lat}" click"lookDetail(marker)"><bm-info-window :title"infoWindow.info.name" :pos…

Deep learning学习记录(课程5)The end

课程名&#xff1a; sequence model 我的理解是时间序列模型 此课程的主要内容是关于时间序列模型&#xff0c;这类模型的特点是数据是一个不定长的序列&#xff0c;且可能随着时间不断的变化。也就是说&#xff0c;每一段数据都有其时间戳&#xff0c;且这个时间戳对于整个数据…

学习Vue 入门到实战——学习笔记(二)

闲聊&#xff1a; 哈哈哈&#xff01;过了好几天才更新博客啦&#xff0c;嘻嘻&#xff0c;马上过年了&#xff0c;大家最近是不是都开心的快飞起来了&#xff0c;小颖好几个朋友公司都已经放假了&#xff0c;可是我们公司要等到腊月29上完班才给放假&#xff0c;哎&#xff01…

【百度地图三 - vue-baidu-map】bm-polyline 组件实现百度地图画线功能

1. 效果图 2. 画线 2.1 html <baidu-map class"bm-view" :scroll-wheel-zoom"true" :center"map.center" :zoom"map.zoom"><bm-polyline :path"lineList" stroke-color"red" :stroke-opacity"0.5…