Thrift通信框架
0 簡介
Thrift是一個軟件通訊框架,用來進行可擴展且跨語言的服務的開發,最初由Facebook於2007年開發,2008年進入Apache開源項目。它結合了功能強大的軟件堆棧和代碼生成引擎,以構建在 C, C++, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, C++Script, Node.js, Smalltalk, and OCaml 等等編程語言間無縫結合的、高效的服務。thrift允許你定義一個簡單的定義文件中的數據類型和服務接口,作為輸入文件,編譯器生成代碼用來方便地生成RPC客戶端和服務器通信的無縫跨編程語言。
1 Thrift的安裝(Windows/C++)
Thrift需要用到幾個開源庫:
1) Boost (http://www.boost.org/)
Boost庫是一個經過千錘百煉、可移植、開源的C++庫,作為C++標准庫的后備,是C++標准化進程的發動機之一,是不折不扣的“准”標准庫,大部分Boost庫的使用只需要包含頭文件即可,少數需要鏈接庫。其中幾個比較有名氣的庫為Regex正則表達式庫、Thread可移植的C++多線程庫、Pool內存池管理庫、smart_ptr智能指針庫等。
2) Libevent (http://libevent.org/)
Libevent是一個由C語言編寫的、輕量級的開源高性能網絡庫,主要特點:事件驅動、高性能、輕量級、專注於網絡、跨平台等。
首先編譯boost和libevent生成對應的lib文件,編譯后文件自動存儲位置為:
.\boost_1_61_0\stage\ (windows下boost庫的簡單編譯)
.\libevent\libevent-2.0.21-stable\ (windows下編譯及使用libevent)
3) 下載、安裝libthrift (https://thrift.apache.org)
下載Thrift壓縮包(v0.9.3),解壓進入\thrift-0.9.3\lib\cpp,使用 VS2010及以上打開Thrift.sln,有libthrift,libthriftnb兩個工程。libthriftnb工程是非阻塞(non-blocking)模式的服務器,非阻塞模式需要依賴libevent庫。檢查所需的include路徑和lib路徑,編譯完成后在\thrift-0.9.1\lib\cpp\Debug(Release)中生成libthrift.lib和libthriftnb.lib。
2 Thrift基礎
(1)數據類型
基本類型:
bool:布爾值,true 或 false,對應 C++ 的 bool
byte:8 位有符號整數,對應 C++ 的 byte
i16:16 位有符號整數,對應 C++ 的 short
i32:32 位有符號整數,對應 C++ 的 int
i64:64 位有符號整數,對應 C++ 的 long
double:64 位浮點數,對應 C++ 的 double
string:utf-8編碼的字符串,對應 C++ 的 string
結構體類型:
struct:定義公共的對象,類似於 C 語言中的結構體定義
容器類型:
list:對應 C++ 的 list
set:對應 C++ 的 set
map:對應 C++ 的map
異常類型:
exception:對應 C++ 的 Exception
服務類型:
service:對應服務的類
(2)通訊支持
支持的數據傳輸協議(傳輸格式)
TBinaryProtocol : 二進制格式.
TCompactProtocol : 壓縮格式
TJSONProtocol : JSON格式
TSimpleJSONProtocol : 提供JSON只寫協議, 生成的文件很容易通過腳本語言解析
tips: 客戶端和服務端的協議要一致
支持的數據傳輸方式
TSocket -阻塞式socker
TFramedTransport–以frame為單位進行傳輸,非阻塞式服務中使用。
TFileTransport – 以文件形式進行傳輸。
TMemoryTransport –將內存用於I/O. java實現時使用了簡單的ByteArrayOutputStream。
TZlibTransport – 使用zlib進行壓縮, 與其他傳輸方式聯合使用。當前無java實現。
支持的服務模型
TSimpleServer – 簡單的單線程服務模型,常用於測試教學使用
TThreadPoolServer – 多線程服務模型,使用標准的阻塞式IO。
TNonblockingServer – 多線程服務模型,使用非阻塞式IO(需使用TFramedTransport數據傳輸方式)
3 一個例子
(1)、編寫idl文件
編寫calculate.idl如下:
1 namespace cpp calculate 2 service Calculator 3 { 4 i32 add(1:i32 add_num1, 2:i32 add_num2), 5 i32 subtract(1:i32 sub_num1, 2:i32 sub_num2) 6 }
(2)、編譯生成框架文件(C++)
Thrift由兩部分組成:編譯器(在compiler目錄下,采用C++編寫)和服務器(在lib目錄下),其中編譯器的作用是將用戶定義的thrift文件編譯生成對應語言的代碼,而服務器是事先已經實現好的、可供用戶直接使用的RPC Server(當然,用戶也很容易編寫自己的server)。
在idl文件所在路徑打開cmd,輸入:thrift-0.9.3.exe --gen cpp calculate.idl
結果代碼存放在gen-cpp目錄下,其中的文件說明:
calculate_constants:idl文件中一些常量的定義
calculate_types:idl文件中定義的數據類型
Calculator:idl文件中定義的服務
Calculator_server.skeleton:給出一個Server端代碼框架
(3)、編寫服務端Server
將Calculator_server.skeleton.cpp內容拷貝,並在main函數開始部分添加代碼:
1 TWinsockSigleton::create(); //高版本不再需要 2 int port = 9090;
(4)、編寫客戶端Client
1 #include "Calculator.h" 2 #include <thrift/transport/TSocket.h> 3 #include <thrift/transport/TBufferTransports.h> 4 #include <thrift/protocol/TBinaryProtocol.h> 5 #include <thrift/server/TSimpleServer.h> 6 #include <thrift/transport/TServerSocket.h> 7 #include <thrift/transport/TBufferTransports.h> 8 9 using namespace apache::thrift; 10 using namespace apache::thrift::protocol; 11 using namespace apache::thrift::transport; 12 using boost::shared_ptr; 13 using namespace ::calculate; 14 int main(int argc, char **argv) 15 { 16 shared_ptr<TSocket> socket(new TSocket("127.0.0.1",9090)); 17 shared_ptr<TTransport> transport(new TBufferedTransport(socket)); 18 shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport)); 19 CalculatorClient client(protocol); 20 try 21 { 22 transport->open(); 23 } 24 catch(TTransportException) 25 { 26 transport->close(); 27 } 28 29 int res_add = client.add(1, 2); 30 printf("client.add(%d, %d) = %d\n", 1, 2, res_add); 31 int res_subtract = client.subtract(3, 2); 32 printf("client.subtract(%d, %d) = %d\n", 3, 2, res_subtract); 33 transport->close(); 34 35 getchar(); 36 return 0; 37 }
注:無論是Client還是Server,都必須包含必要的頭文件和鏈接所需要的靜態庫文件。
包含目錄:工程配置頁,C/C++ -> General -> Additional Include Directories
庫目錄:工程配置頁,Linker -> General -> Additional Library Directories,並在Input -> Additional Dependencies加入lib
除此之外,還需要OpenSSL的包含路徑和庫路徑,安裝后指定即可。
通過上面的例子分析可以看出,Thrift最重要的組件是編譯器(采用C++編寫),它為用戶生成了網絡通信相關的代碼,從而大大減少了用戶的編碼工作。
Thrift采用了C/S模型,不支持雙向通信:client只能遠程調用server端的RPC接口,但client端則沒有RPC供server端調用,這意味着,client端能夠主動與server端通信,但server端不能主動與client端通信而只能被動地對client端的請求作出應答。這種RPC模式在某些應用中存在缺陷,比如:有些應用,在大部分情況下,client端會主動向server端發請求或者向server端發送數據,而在少部分情況下,server端也需要主動向client發送一些命令,告知進行某些操作。為了解決該問題,通常使用雙client/server,通信雙方都既是client,也是server。該方案需要在通信雙方之間建立兩個通信通道,開啟兩個端口,這比較繁瑣,且很不優雅。但仍是目前普遍采用的一套方案。
相關資料
l Apache Thrift 在Windows下的安裝與開發
l Thrift: Scalable Cross-Language Services Implementation
PS:
CSDN提問:有沒有人在windows下,用VS2010成功運行過thrift的程序?
CSDN下載:解決在thrift0.9.3 cpp lib編譯時候出現的問題
需要例子源碼的可給我留言~
