1. 程式人生 > >Thrift基本流程

Thrift基本流程

1. Thrift類介紹 
Thrift程式碼包(位於thrift-0.6.1/lib/cpp/src)有以下幾個目錄:

concurrency:併發和時鐘管理方面的庫
processor:Processor相關類
protocal:Protocal相關類
transport:transport相關類
server:server相關類

  1.1 Transport類(how is transmitted?)
負責資料傳輸,有以下幾個可用類:
TFileTransport:檔案(日誌)傳輸類,允許client將檔案傳給server,允許server將收到的資料寫到檔案中;
THttpTransport:採用Http傳輸協議進行資料傳輸;
TSocket:採用TCP Socket進行資料傳輸;
TZlibTransport:壓縮後對資料進行傳輸,或者將收到的資料解壓。 下面幾個類主要是對上面幾個類地裝飾(採用了裝飾模式),以提高傳輸效率。
TBufferedTransport:對某個Transport物件操作的資料進行buffer,即從buffer中讀取資料進行傳輸,或者將資料直接寫入buffer;
TFramedTransport:同TBufferedTransport類似,也會對相關資料進行buffer,同時,它支援定長資料傳送和接收;
TMemoryBuffer:從一個緩衝區中讀寫資料。
1.2 Protocol類(what is transmitted?)

負責資料編碼,主要有以下幾個可用類:
TBinaryProtocol:二進位制編碼
TJSONProtocol:JSON編碼
TCompactProtocol:密集二進位制編碼
TDebugProtocol:以使用者易讀的方式組織資料 1.3 Server類(providing service for clients)
TSimpleServer:簡單的單執行緒伺服器,主要用於測試
TThreadPoolServer:使用標準阻塞式IO的多執行緒伺服器
TNonblockingServer:使用非阻塞式IO的多執行緒伺服器,TFramedTransport必須使用該型別的server
1.5 物件序列化和反序列化 
Thrift中的Protocol負責對資料進行編碼,因而可使用Protocol相關物件進行序列化和反序列化。     2.編寫client和server   2.1 client端程式碼編寫
Client編寫的方法分為以下幾個步驟:
(1) 定義TTransport,為你的client設定傳輸方式(如socket, http等)。
(2) 定義Protocal,使用裝飾模式(Decorator設計模式)封裝TTransport,為你的資料設定編碼格式(如二進位制格式,JSON格式等)
(3) 例項化client物件,呼叫服務介面。
說明:如果使用者在thrift檔案中定義了一個叫${server_name}的service,則會生成一個叫${server_name}Client的物件。   2.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程式碼(樁),     3.示例:  

1. thrift生成程式碼

建立Thrift檔案:G:\test\thrift\demoHello.thrift ,內容如下:

  namespace java com.micmiu.thrift.demo   service  HelloWorldService {   string sayHello(1:string username) }
thrift-0.8.0.exe 是官網提供的windows下編譯工具,運用這個工具生成相關程式碼: thrift-0.8.0.exe -r -gen java ./demoHello.thrift   將生成的HelloWorldService.java 檔案copy到自己測試的工程中,我的工程是用maven構建的,故在pom.xml中增加如下內容:   <dependency>
     <groupId>org.apache.thrift</groupId>
     <artifactId>libthrift</artifactId>
     <version>0.8.0</version>
</dependency>
<dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-log4j12</artifactId>
     <version>1.5.8</version>
</dependency>  

2. 實現介面Iface

java程式碼:HelloWorldImpl.java   package com.micmiu.thrift.demo;
import org.apache.thrift.TException;

public class HelloWorldImpl implements HelloWorldService.Iface {
     public HelloWorldImpl() {
     }
     @Override
     public String sayHello(String username) throws TException {
          return "Hi," + username + " welcome to my blog www.micmiu.com";
     }
}  

3.TSimpleServer服務端

簡單的單執行緒服務模型,一般用於測試。

編寫服務端server程式碼:HelloServerDemo.java   package com.micmiu.thrift.demo;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TJSONProtocol;
import org.apache.thrift.protocol.TSimpleJSONProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;

public class HelloServerDemo {
     public static final int SERVER_PORT = 8090;
     public void startServer() {
          try {
               System.out.println("HelloWorld TSimpleServer start ....");
               TProcessor tprocessor = new HelloWorldService.Processor&lt;HelloWorldService.Iface&gt;(
                         new HelloWorldImpl());
               // HelloWorldService.Processor&lt;HelloWorldService.Iface&gt; tprocessor =
               // new HelloWorldService.Processor&lt;HelloWorldService.Iface&gt;(
               // new HelloWorldImpl());
               // 簡單的單執行緒服務模型,一般用於測試
               TServerSocket serverTransport = new TServerSocket(SERVER_PORT);
               TServer.Args tArgs = new TServer.Args(serverTransport);
               tArgs.processor(tprocessor);
               tArgs.protocolFactory(new TBinaryProtocol.Factory());
               // tArgs.protocolFactory(new TCompactProtocol.Factory());
               // tArgs.protocolFactory(new TJSONProtocol.Factory());
               TServer server = new TSimpleServer(tArgs);
               server.serve();
          } catch (Exception e) {
               System.out.println("Server start error!!!");
               e.printStackTrace();
          }
     }
     /**
     * @param args
     */
     public static void main(String[] args) {
          HelloServerDemo server = new HelloServerDemo();
          server.startServer();
     }
}   編寫客戶端Client程式碼:HelloClientDemo.java   package com.micmiu.thrift.demo;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TJSONProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;

public class HelloClientDemo {
     public static final String SERVER_IP = "localhost";
     public static final int SERVER_PORT = 8090;
     public static final int TIMEOUT = 30000;
     /**
     *
     * @param userName
     */
     public void startClient(String userName) {
          TTransport transport = null;
          try {
               transport = new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT);
               // 協議要和服務端一致
               TProtocol protocol = new TBinaryProtocol(transport);
               // TProtocol protocol = new TCompactProtocol(transport);
               // TProtocol protocol = new TJSONProtocol(transport);
               HelloWorldService.Client client = new HelloWorldService.Client(
                         protocol);
               transport.open();
               String result = client.sayHello(userName);
               System.out.println("Thrify client result =: " + result);
          } catch (TTransportException e) {
               e.printStackTrace();
          } catch (TException e) {
               e.printStackTrace();
          } finally {
               if (null != transport) {
                    transport.close();
               }
          }
     }
     /**
     * @param args
     */
     public static void main(String[] args) {
          HelloClientDemo client = new HelloClientDemo();
          client.startClient("Michael");
     }
}  

先執行服務端程式,日誌如下:

  HelloWorld TSimpleServer start ....

再執行客戶端呼叫程式,日誌如下:

  Thrify client result =: Hi,Michael welcome to my blog www.micmiu.com

測試成功,和預期的返回資訊一致。

    總結:Server端和client端編碼基本步驟  

1.服務端編碼基本步驟:

  • 實現服務處理介面impl
  • 建立TProcessor
  • 建立TServerTransport
  • 建立TProtocol
  • 建立TServer
  • 啟動Server

2.客戶端編碼基本步驟:

  • 建立Transport
  • 建立TProtocol
  • 基於TTransport和TProtocol建立 Client
  • 呼叫Client的相應方法
    參考資料: http://www.micmiu.com/soa/rpc/thrift-sample/
                http://dongxicheng.org/search-engine/thrift-rpc/