程序員必知的開源軟件 之 Thrift

開源軟件 程序員 軟件 Apache 機器學習的世界 2017-06-18

Thrift是apache的一個開源框架,此框架抽取出C/S的必要元素,將基本的網絡通信進行封裝,降低了網絡開發的難度。在thrift文件的基礎上,使用Thrift提供的工具(thrift等)可以自動生成程序的框架代碼,使程序員將注意力只集中在通信接口以及C/S各自的邏輯上。

程序員必知的開源軟件 之 Thrift

Thrift框架

thrift文件


thrift文件是定義C/S通信的接口文件,在此文件中定義了server提供哪些遠程訪問接口(service),以及需要操作哪些類型的數據(struct),以及在操作過程中出現的異常(exception)。

1. service

thrift會在server端的代碼中自動生成service的接口(未實現),程序員在其中實現需要提供的服務邏輯即可,同時client端代碼中也會實現與service同名的接口(已實現),用於給串行化需要給server端傳遞的數據。例如,在thrift中定義瞭如下service:

service HeartBeatProtocal { HeartBeatResponse heartbeat(1: HeartBeatMessage msg) }

通過thrift自動生成的代碼中,service端就會有如下的接口生成:

void heartbeat(HeartBeatResponse& _return, const HeartBeatMessage& msg) { // Your implementation goes here }

client端則會有如下同名接口的實現:

void HeartBeatProtocalClient::heartbeat(HeartBeatResponse& return, const HeartBeatMessage& msg) { sendheartbeat(msg); recvheartbeat(return); }

因此程序員需要完成的工作僅有兩點:

  • 實現server端的service接口;

  • 在client程序中調用與service接口同名的函數來完成通信

2. struct

C/S程序必然是為了完成信息的交互,無論是server給client提供請求的數據,還是client向server傳送需要存儲的數據,其中數據是核心。在thrift數據的格式就是由一些內置的基礎數據類型,以及struct組成複合數據類型來組成。

thrift內置了大多數用到的數據類型,具體如下:

  • bool bool型變量

  • byte 有符號字符型變量

  • i16 有符號16位整形變量

  • i32 有符號32位整形變量

  • i64 有符號64位整形變量

  • double 64位寬的浮點型變量

  • string C++中的string類變量

  • binary 二進制數據,一系列byte型變量的集合

  • map

    key-value型變量

  • list

    有序列表

  • set

    集合,集合中的每個元素唯一

通過struct將上述基礎數據類型組合起來就形成了程序中需要傳輸的數據類型。struct格式如下:

struct HostInfo { 1: string hostname, 2: string ipaddr }

thrift會為自定義的struct生成對應的class,以及相應的接口函數。

thrift工具


完成了thrift文件的編寫後,需要藉助thrift來自動生成相應的代碼。命令具體格式如下:

thrift --gen program_language thrift_file

示例


為了試用thrift,下面實現一個簡單的master-agent模式的程序。agent負責在服務器上搜集配置信息,例如主機名、CPU信息、內存信息等,master負責在遠程服務器上彙總各agent的信息,並存儲起來。

程序員必知的開源軟件 之 Thrift

master-slave結構

1. 編寫thrift文件

在這個例子中,master僅需要提供一個服務,就是接受agent傳送過來的數據並存儲起來。所以,需要在thrift文件中定義一個service,它需要接受agent傳送過來的信息,並給agent返回一個時間戳表示數據已成功接收到並存儲起來:

service HeartBeatProtocal { HeartBeatResponse heartbeat(1: HeartBeatMessage msg) }

如上所述,其接口需要兩個數據類型,一個是agent傳送給master的基礎信息數據HeartBeatMessage,另一個是master返回給agent的相關信息HeartBeatResponse,因此在thrift中定義相關的struct:

struct HostInfo { 1: string hostname, 2: string ipaddr }

struct CpuInfo { 1: i32 cpuNum, 2: string cpuModel }

struct DimmInfo { 1: i32 dimmCap, 2: string dimmModel }

struct MemInfo { 1: i32 memNum, 2: map dimmInfo }

struct HeartBeatMessage { 1: i32 timestamp, 2: HostInfo hostInfo, 3: CpuInfo cpuInfo, 4: MemInfo memInfo, 5: bool firstHeartBeat }

struct HeartBeatResponse { 1: i32 timestamp }

2. 自動生成代碼

運行thrift --gen cpp HeartBeat.thrift,在gen-cpp目錄下即生成了相關的代碼。

3. 實現服務端邏輯

在本實例中,server僅提供一個service heartbeat,因此在HeartBeatProtocalServer.cpp文件中(thrift生成的文件原名為HeartBeatProtocal_server.skeleton.cpp)的HeartBeatProtocalHandler類中實現heartbeat接口:

void heartbeat(HeartBeatResponse& _return, const HeartBeatMessage& msg) {

// Your implementation goes here

}

4. 實現客戶端程序

thrift是不會自動生成客戶端程序的,為了實現客戶端程序,需要對thrift中通信的類和接口有個初步的瞭解,相關知識將在另一片博客中介紹,這裡僅提供相關代碼:

int main(int argc, char *argv[]) { boost::sharedptr socket(new TSocket("10.32.64.221", 9090)); boost::sharedptr transport(new TBufferedTransport(socket)); boost::shared_ptr protocol(new TBinaryProtocol(transport));

HeartBeatProtocalClient client(protocol);

}

5. 實現Makefile文件

GENSRC := HeartBeatconstants.cpp HeartBeatProtocal.cpp HeartBeattypes.cpp getinfo.cpp GENOBJ := $(patsubst %.cpp, %.o, $(GENSRC))

INCLUDEDIR := /home/lsy/third-64/thrift/include/ LIBDIR := /home/lsy/third-64/thrift/lib/

.PHONY: all clean

all: HeartBeatProtocalServer HeartBeatProtocalClient

%.o: %.cpp $(CXX) -Wall -DHAVEINTTYPESH -DHAVENETINETINH -I$(INCLUDEDIR) -c $< -o $@

HeartBeatProtocalServer: HeartBeatProtocalServer.o $(GENOBJ) $(CXX) $^ -o $@ -L$(LIBDIR) -lthrift

HeartBeatProtocalClient: HeartBeatProtocalClient.o $(GENOBJ) $(CXX) $^ -o $@ -L$(LIBDIR) -lthrift

clean: $(RM) *.o HeartBeatProtocalServer

總結


thrift的確簡化了網絡通信的大量操作,使程序員能集中精力在具體的邏輯,以及數據交互格式上,另外由於使用經過認證的框架,也大大提高了程序的可靠性。

程序員必知的開源軟件 之 Thrift

Thrift簡化了程序間通信

相關推薦

推薦中...