1. 程式人生 > >Thrift_簡介(基於C#)

Thrift_簡介(基於C#)

/*
 * Thrift的RPC呼叫的一個完整流程:
 * 首先是通過Thrift的編譯器生成的客戶端,將呼叫資訊(方法名,引數資訊)以指定的協議進行封裝,
 * 而傳輸層TTransport是對協議層的封裝進行處理(比如封裝成幀frame),並通過網路傳送出去。
 * 服務端這邊流程跟客戶端相反,收到客戶端發過來的資料後,首先經過傳輸層對傳過來的資料進行處理,
 * 然後使用特定的協議(跟客戶端是一一對應的)進行解析,然後再通過生成的Processor呼叫使用者編寫的程式碼,
 * 如果有返回值的話,返回值以逆向的順序,即通過協議層封裝,然後傳輸層處理對資料進行傳送,
 * 到了客戶端那邊就是對服務端返回的資料進行處理,使用特定協議進行解析,然後得到一個呼叫個的結果。
 * 
 *  基本型別
 *  bool:布林值(true或者false)
 *  byte:8位的有符號位元組(byte型別)
 *  i16:16位的有符號整數(short型別)
 *  i32:32位的有符號整數(int型別)
 *  i64:64位的有符號長整型(long型別)
 *  double:一個64位的浮點數(double型別)
 *  string: 一個utf8編碼的字串文字(String) 
 *  
 *  集合型別
 *  list:一個有序的元素列表。元素可以重複。
 *  set:一個無序的元素集合,集合中元素不能重複。
 *  map:一個鍵值對的資料結構,相當於Java中的HashMap。
 * 
 *  異常型別Exceptions
 *  Thrift的異常型別,除了是繼承於靜態異常基類以外,其他的跟struct是類似的。表示的是一個異常物件。
 *  
 *  服務型別Services Server: 4.服務層, 整合上述元件, 提供網路模型(單執行緒/多執行緒/事件驅動), 最終形成真正的服務.
 *  Thrift 的service型別相當於定義一個面向物件程式設計的一個介面。Thrift的編譯器會根據這個介面定義來生成服務端和客戶端的介面實現程式碼。
 *  
 *  Thrift的傳輸格式(協議層)1.protocol: 協議層, 定義資料傳輸格式,可以為二進位制或者XML等
 *  TBinaryProtocol: 二進位制格式。效率顯然高於文字格式
 *  TCompactProtocol:壓縮格式。在二進位制基礎上進一步壓縮。
 *  TJSONProtocol:JSON格式。
 *  TSimpleJSONProtocol:提供JSON只寫協議(缺少元資料資訊),生成的檔案很容易用過指令碼語言解析。
 *  TDebugProtocol:使用易懂的刻度文字格式,以便於除錯。
 *  
 *  Thrift的資料傳輸方式(傳輸層) 2. Transport: 傳輸層,定義資料傳輸方式,可以為TCP/IP傳輸,記憶體共享或者檔案共享等
 *  TSocket:阻塞式socket。
 *  TFramedTransport:以frame為單位進行傳輸,非阻塞式服務中使用。
 *  TFileTransport:以檔案形式進行傳輸。
 *  TMemoryTransport:將記憶體用於I/O,Java是現實內部實際使用了簡單的ByteArrayOutputStream。
 *  TZlibTransport:使用zlib進行壓縮,與其他傳輸方式聯合使用。當前無java實現。
 *  
 *  Thrift的服務模型 Processor: 3. 處理層, 這部分由定義的idl來生成, 封裝了協議輸入輸出流, 並委託給使用者實現的handler進行處理.
 *  TSimpleServer: 簡單的單執行緒服務模型,常用於測試。只在一個單獨的執行緒中以阻塞I/O的方式來提供服務。所以它只能服務一個客戶端連線,其他所有客戶端在被伺服器端接受之前都只能等待。
 *  TNonblockingServer: 它使用了非阻塞式I/O,使用了java.nio.channels.Selector,通過呼叫select(),它使得程式阻塞在多個連線上,而不是單一的一個連線上。TNonblockingServer處理這些連線的時候,要麼接受它,要麼從它那讀資料,要麼把資料寫到它那裡,然後再次呼叫select()來等待下一個準備好的可用的連線。通用這種方式,server可同時服務多個客戶端,而不會出現一個客戶端把其他客戶端全部“餓死”的情況。缺點是所有訊息是被呼叫select()方法的同一個執行緒處理的,服務端同一時間只會處理一個訊息,並沒有實現並行處理。
 *  THsHaServer:(半同步半非同步server) 針對TNonblockingServer存在的問題,THsHaServer應運而生。它使用一個單獨的執行緒專門負責I/O,同樣使用java.nio.channels.Selector,通過呼叫select()。然後再利用一個獨立的worker執行緒池來處理訊息。只要有空閒的worker執行緒,訊息就會被立即處理,因此多條訊息能被並行處理。效率進一步得到了提高。
 *  TThreadedSelectorServer: 它與THsHaServer的主要區別在於,TThreadedSelectorServer允許你用多個執行緒來處理網路I/O。它維護了兩個執行緒池,一個用來處理網路I/O,另一個用來進行請求的處理。
 *  TThreadPoolServer: 它使用的是一種多執行緒服務模型,使用標準的阻塞式I/O。它會使用一個單獨的執行緒來接收連線。一旦接受了一個連線,它就會被放入ThreadPoolExecutor中的一個worker執行緒裡處理。worker執行緒被繫結到特定的客戶端連線上,直到它關閉。一旦連線關閉,該worker執行緒就又回到了執行緒池中。 這意味著,如果有1萬個併發的客戶端連線,你就需要執行1萬個執行緒。所以它對系統資源的消耗不像其他型別的server一樣那麼“友好”。此外,如果客戶端數量超過了執行緒池中的最大執行緒數,在有一個worker執行緒可用之前,請求將被一直阻塞在那裡。 如果提前知道了將要連線到伺服器上的客戶端數量,並且不介意執行大量執行緒的話,TThreadPoolServer可能是個很好的選擇
 *  
 *  cmd命令:
 *  thrift-0.9.1.exe -help
 *  thrift-0.9.1.exe -r -gen java data.thrift
 *  thrift-0.9.1.exe -r -gen py data.thrift
 *  thrift-0.9.1.exe -r -gen csharp  data.thrift
 
*/ using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; using System.Threading.Tasks; using System.Collections; using Thrift.Transport;
using Thrift.Server; using Thrift.Protocol; namespace TestThriftProject { public partial class FrmTest : Form { public FrmTest() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) {
if (textBox1.Text != null) { TTransport transport = new TSocket("127.0.0.1", 8090, 3000); TProtocol protocol = new TBinaryProtocol(transport);//協議要和服務端一致 HelloWorldService.Client client = new HelloWorldService.Client(protocol); try { transport.Open(); String result = client.SayHello(textBox1.Text.Trim()); Console.WriteLine("Thrift client result =: " + result); } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); } finally { if (transport != null) { transport.Close(); } } } } private void FrmTest_Load(object sender, EventArgs e) { new Task(new Action(() => { try { TServerSocket serverTransport = new TServerSocket(8090, 0, false); HelloWorldService.Processor processor = new HelloWorldService.Processor(new HelloWroldImpl()); TServer server = new TSimpleServer(processor, serverTransport); server.Serve(); } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); } })).Start(); } } }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace TestThriftProject
{
    public class HelloWroldImpl : HelloWorldService.Iface
    {
        public string SayHello(string username)
        {
            return  string.Format("{0:yyyy/MM/dd hh:mm:ss} hello: {1}", DateTime.Now, username);
        }
    }
}