C++庫(Thrift)


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  董的博客Thirft框架介紹

  l  董的博客Thrift使用指南

  l  董的博客使用Thrift RPC編寫程序

  l  董的博客淺談Thrift內部實現原理

  l  Thrift: Scalable Cross-Language Services Implementation

  PS: 

  CSDN提問:有沒有人在windows下,用VS2010成功運行過thrift的程序?

  CSDN下載:解決在thrift0.9.3 cpp lib編譯時候出現的問題

  需要例子源碼的可給我留言~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM