日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用Thrift RPC编写程序

發布時間:2024/4/17 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用Thrift RPC编写程序 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?http://dongxicheng.org/search-engine/thrift-rpc/

1. 概述

本文以C++語言為例介紹了thrift RPC的使用方法,包括對象序列化和反序列化,數據傳輸和信息交換等。

本文采用了一個示例進行說明,該示例主要完成傳輸(上報日志或者報表)功能,該示例會貫穿本文,內容涉及thrift定義,代碼生成,thrift類說明,client編寫方法,server編寫方法等。

關于Thrift架構分析,可參考:Thrift架構介紹

關于Thrift文件編寫方法,可參考:Thrift使用指南。

2. 示例描述

假設我們要使用thrift RPC完成一個數據傳輸任務,數據格式和PRC接口用一個thrift文件描述,具體如下:

(1) book.thrift,用于描述書籍信息的thrift接口

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 //book.thrift, ?? namespace cpp example ?? struct Book_Info { ?? 1: i32 book_id, ?? 2: string book_name, ?? 3: string book_author, ?? 4: double book_price, ?? 5: string book_publisher, ?? }

(2) rpc.thrift,client向server傳輸數據(上報日志或者報表)的RPC接口

1 2 3 4 5 6 7 8 9 10 11 12 13 14 //rpc.thrift ?? namespace cpp example ?? include "book.thrift" ?? service BookServlet { ?? bool Sender(1: list<book.Book_Info> books); ?? oneway void Sender2(1: list<book.Book_Info> books); ?? }

說明:該thrift文件定義了一個service,它包含兩個接口,server端需要實現這兩個接口以對client提供服務。其中,第一個接口函數是阻塞式的,即要等待server返回值以后才能繼續,另外一個聲明為oneway類型(返回值為void),表明該函數是非阻塞式的,將數據發給server后不必等待返回結果,但使用該函數時,需要考慮server的承受能力,適度的調整發送頻率。

3. Thrift文件與生成的代碼對應關系

每個thrift文件會產生四個文件,分別為:${thrift_name}_constants.h,${thrift_name}_constants.cpp,${thrift_name}_types.h,${thrift_name}_types.cpp

對于含有service的thrift文件,會額外生成兩個文件,分別為:${service_name}.h,${service_name}.cpp

對于含有service的thrift文件,會生成一個可用的server樁:${service_name}._server.skeleton.cpp

對于本文中的例子,會產生以下文件:

book_constants.h book_constants.cpp

book_types.h book_types.cpp

rpc_constants.h rpc_constants.cpp

rpc_types.h rpc_types.cpp

BookServlet.h BookServlet.cpp

BookServlet_server.skeleton.cpp

4. Thrift類介紹

Thrift代碼包(位于thrift-0.6.1/lib/cpp/src)有以下幾個目錄:

concurrency:并發和時鐘管理方面的庫

processor:Processor相關類

protocal:Protocal相關類

transport:transport相關類

server:server相關類

4.1 Transport類(how is transmitted?)

負責數據傳輸,有以下幾個可用類:

TFileTransport:文件(日志)傳輸類,允許client將文件傳給server,允許server將收到的數據寫到文件中。

THttpTransport:采用Http傳輸協議進行數據傳輸

TSocket:采用TCP Socket進行數據傳輸

TZlibTransport:壓縮后對數據進行傳輸,或者將收到的數據解壓

下面幾個類主要是對上面幾個類地裝飾(采用了裝飾模式),以提高傳輸效率。

TBufferedTransport:對某個Transport對象操作的數據進行buffer,即從buffer中讀取數據進行傳輸,或者將數據直接寫入buffer

TFramedTransport:同TBufferedTransport類似,也會對相關數據進行buffer,同時,它支持定長數據發送和接收。

TMemoryBuffer:從一個緩沖區中讀寫數據

4.2 Protocol類(what is transmitted?)

負責數據編碼,主要有以下幾個可用類:

TBinaryProtocol:二進制編碼

TJSONProtocol:JSON編碼

TCompactProtocol:密集二進制編碼

TDebugProtocol:以用戶易讀的方式組織數據

4.3 Server類(providing service for clients)

TSimpleServer:簡單的單線程服務器,主要用于測試

TThreadPoolServer:使用標準阻塞式IO的多線程服務器

TNonblockingServer:使用非阻塞式IO的多線程服務器,TFramedTransport必須使用該類型的server

5. 對象序列化和反序列化

Thrift中的Protocol負責對數據進行編碼,因而可使用Protocol相關對象進行序列化和反序列化。

由于對象序列化和反序列化不設計傳輸相關的問題,所以,可使用TBinaryProtocol和TMemoryBuffer,具體如下:

(1) 使用thrift進行對象序列化

//對對象object進行序列化,保存到str中

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 template <typename Type> ?? void Object2String(Type& object, string &str) { ?? ??shared_ptr<TMemoryBuffer> membuffer(new TMemoryBuffer()); ?? ??shared_ptr<TProtocol> protocol(new TBinaryProtocol(membuffer)); ?? ??object.write(protocol.get()); ?? ??str.clear(); ?? ??str = membuffer.getBufferAsString(); ?? }

(2)使用thrift進行對象反序列化

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 //對str中保存的對象進行反序列化,保存到object中 ?? template <typename Type> ?? void String2Object(string& buffer, Type &object) { ?? ??shared_ptr<TMemoryBuffer> membuffer(new TMemoryBuffer( ?? ??reinterpret_cast<uint*>(buffer.data()))); ?? ??shared_ptr<TProtocol> protocol(new TBinaryProtocol(membuffer)); ?? ??object.read(protocol.get()); ?? }

6. 編寫client和server

6.1 client端代碼編寫

Client編寫的方法分為以下幾個步驟:

(1) 定義TTransport,為你的client設置傳輸方式(如socket, http等)。

(2) 定義Protocal,使用裝飾模式(Decorator設計模式)封裝TTransport,為你的數據設置編碼格式(如二進制格式,JSON格式等)

(3) 實例化client對象,調用服務接口。

說明:如果用戶在thrift文件中定義了一個叫${server_name}的service,則會生成一個叫${server_name}Client的對象,比如,我給出的例子中,thrift會自動生成一個叫BookServletClient的類,Client端的代碼編寫如下:

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 #include " gen-cpp/BookServlet.h" //一定要包含該頭文件 ?? //其頭文件,其他using namespace ……. ?? int main(int argc, char** argv) { ?? ??shared_ptr<TTransport> socket(new TSocket("localhost", 9090)); ?? ??shared_ptr<TTransport> transport(new TBufferedTransport(socket)); ?? ??shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport)); ?? ??example::BookServletClient client(protocol); ?? try { ?? ??transport->open(); ?? ??vector<example::Book_Info> books; ?? ??…... ?? ??client.Sender(books);//RPC函數,調用serve端的該函數 ?? ??transport->close(); ?? } catch (TException &tx) { ?? ??printf("ERROR: %s\n", tx.what()); ?? } ?? }

6.2 Server端代碼編寫

(1) 定義一個TProcess,這個是thrift根據用戶定義的thrift文件自動生成的類

(2) 使用TServerTransport獲得一個TTransport

(3) 使用TTransportFactory,可選地將原始傳輸轉換為一個適合的應用傳輸(典型的是使用TBufferedTransportFactory)

(4) 使用TProtocolFactory,為TTransport創建一個輸入和輸出

(5) 創建TServer對象(單線程,可以使用TSimpleServer;對于多線程,用戶可使用TThreadPoolServer或者TNonblockingServer),調用它的server()函數。

說明:thrift會為每一個帶service的thrift文件生成一個簡單的server代碼(樁),在例子中,thrift會生成BookServlet_server.skeleton.cpp,用戶可以在這個文件基礎上實現自己的功能。

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 73 74 75 76 #include "gen-cpp/BookServlet.h" ?? #include <protocol/TBinaryProtocol.h> ?? #include <server/TSimpleServer.h> ?? #include <transport/TServerSocket.h> ?? #include <transport/TBufferTransports.h> ?? using namespace ::apache::thrift; ?? using namespace ::apache::thrift::protocol; ?? using namespace ::apache::thrift::transport; ?? using namespace ::apache::thrift::server; ?? using boost::shared_ptr; ?? using namespace example; ?? class BookServletHandler : virtual public BookServletIf { ?? public: ?? BookServletHandler() { ?? // Your initialization goes here ?? } ?? //用戶需實現這個接口 ?? bool Sender(const std::vector<example::Book_Info> & books) { ?? ??// Your implementation goes here ?? ??printf("Sender\n"); ?? } ?? //用戶需實現這個接口 ?? void Sender2(const std::vector<example::Book_Info> & books) { ?? ??// Your implementation goes here ?? ??printf("Sender2\n"); ?? } ?? }; ?? int main(int argc, char **argv) { ?? ??int port = 9090; ?? ??shared_ptr<BookServletHandler> handler(new BookServletHandler()); ?? ??shared_ptr<TProcessor> processor(new BookServletProcessor(handler)); ?? ??shared_ptr<TServerTransport> serverTransport(new TServerSocket(port)); ?? ??shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory()); ?? ??shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory()); ?? ??TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory); ?? ??server.serve(); ?? ??return 0; ?? }

7. 總結

至此,關于thrift框架的三篇文章已經全部完成,包括:

(1) Thrift框架介紹: Thrift框架介紹

(2) Thrift文件編寫方法: Thrift使用指南

(3) Thrift RPC使用方法:利用Thrift RPC編寫程序

與thrift類似的開源RPC框架還有google的protocal buffer,它雖然支持的語言比較少,但效率更高,因而受到越來越多的關注。

由于thrift開源時間很早,經受了時間的驗證,因而許多系統更愿意采用thrift,如Hadoop,Cassandra等。

附:thrift與protocal buffer比較

從上面的比較可以看出,thrift勝在“豐富的特性“上,而protocal buffer勝在“文檔化”非常好上。在具體實現上,它們非常類似,都是使用唯一整數標記字段域,這就使得增加和刪除字段與不會破壞已有的代碼。

它們的最大區別是thrift支持完整的client/server RPC框架,而protocal buffer只會產生接口,具體實現,還需要用戶做大量工作。

另外,從序列化性能上比較,Protocal Buffer要遠遠優于thrift,具體可參考:http://www.ibm.com/developerworks/cn/linux/l-cn-gpb/?ca=drs-tp4608 。

8. 參考資料

(1) http://stuartsierra.com/2008/07/10/thrift-vs-protocol-buffers

(2) Thrift: Scalable Cross-Language Services Implementation. Mark Slee, Aditya Agarwal and Marc Kwiatkowski. Facebook

(3) Thrift網站:http://thrift.apache.org/

(4) Protocal Buffer網站:

http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/overview.html

原創文章,轉載請注明: 轉載自董的博客

?

總結

以上是生活随笔為你收集整理的使用Thrift RPC编写程序的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。