Thrift實踐(C++)

文章簡介

運用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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章