Thrift 入門教程


1. 概述  

  thrift是一個軟件框架,用來進行可擴展且跨語言的服務的開發。它結合了功能強大的軟件堆棧和代碼生成引擎,以構建在 C++, Java, Go,Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 這些編程語言間無縫結合的、高效的服務。Thrift允許定義一個簡單的定義文件中的數據類型和服務接口,以作為輸入文件,編譯器生成代碼用來方便地生成RPC客戶端和服務器通信的無縫跨編程語言。thrift最初由facebook開發用做系統內各語言之間的RPC通信 。2007年由facebook貢獻到apache基金 ,08年5月進入apache孵化器 。

2. thrift 的跨語言特性

  thrift通過一個中間語言IDL(接口定義語言)來定義RPC的數據類型和接口,這些內容寫在以.thrift結尾的文件中,然后通過特殊的編譯器來生成不同語言的代碼,以滿足不同需要的開發者,比如java開發者,就可以生成java代碼,c++開發者可以生成c++代碼,生成的代碼中不但包含目標語言的接口定義,方法,數據類型,還包含有RPC協議層和傳輸層的實現代碼。

3. thrift 的協議棧結構

thrift是一種c/s的架構體系.在最上層是用戶自行實現的業務邏輯代碼.第二層是由thrift編譯器自動生成的代碼,主要用於結構化數據的解析,發送和接收。TServer主要任務是高效的接受客戶端請求,並將請求轉發給Processor處理。Processor負責對客戶端的請求做出響應,包括RPC請求轉發,調用參數解析和用戶邏輯調用,返回值寫回等處理。從TProtocol以下部分是thirft的傳輸協議和底層I/O通信。TProtocol是用於數據類型解析的,將結構化數據轉化為字節流給TTransport進行傳輸。TTransport是與底層數據傳輸密切相關的傳輸層,負責以字節流方式接收和發送消息體,不關注是什么數據類型。底層IO負責實際的數據傳輸,包括socket、文件和壓縮數據流等。

 4. thrift java 實例

4.1 創建一個服務HelloWorld

(1)創建文件Hello.thrift,代碼如下:
namespace java org.wavemelody.thrift.demo

service  HelloWorldService {
  string sayHello(1:string username)
}

這里定義了一個HelloWorldService 服務,包含一個sayHello方法,入參和返回值都是一個string類型的參數。

(2)thrift生成代碼
thrift-0.11.0.exe -r -gen java HelloWorldService.thrift
thrift-0.11.0.exe是官網提供的windows下編譯工具,運用這個工具生成相關代碼,生成后的目錄結構如下:

thrift-0.11.0.exe
HelloWorldService.thrift
gen-java
  |--org
    |--wavemelody
      |--thrift
        |--demo
          |--HelloWorldService.java

將生成的 HelloWorldService.java 拷貝到自己的工程中,注意包路徑。

(3)實現Iface

 HelloWorldServiceImpl.java

package org.wavemelody.thrift.demo;

import org.apache.thrift.TException;

/**
 * Created by Andy on 2018/8/14.
 */
public class HelloWorldServiceImpl implements HelloWorldService.Iface{
    @Override
    public String helloString(String para) throws TException {
        return "Hello " + para;
    }
}
(4) 創建TSimpleServer服務端

創建服務器端實現代碼,將 HelloServiceImpl 作為具體的處理器傳遞給 Thrift 服務器,代碼如下:

HelloServiceServer.java

package org.wavemelody.thrift.demo;

import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;

/**
 * Created by Andy on 2018/8/14.
 */
public class HelloServiceServer {
    public void startServer(){
        try {
         System.out.println(
"HelloWorldServer start ... "); TServerSocket serverTransport = new TServerSocket(8888); TServer.Args tArgs = new TServer.Args(serverTransport); TProcessor tProcessor = new HelloWorldService.Processor<HelloWorldService.Iface>(new HelloWorldServiceImpl()); 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 (TTransportException e) { e.printStackTrace(); } } public static void main(String[] args){ HelloServiceServer serviceServer = new HelloServiceServer(); serviceServer.startServer(); } }
(5)編寫客戶端Client代碼
HelloServiceClient.java
package org.wavemelody.thrift.demo;

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;

/**
 * Created by Andy on 2018/8/14.
 */
public class HelloServiceClient {
    public void startClient(String username){
        TTransport tTransport = null;
        try {
            tTransport = new TSocket("localhost",8888,30000);
            // 協議要和服務端一致
            TProtocol protocol = new TBinaryProtocol(tTransport);
//            TProtocol protocol = new TCompactProtocol(tTransport);
//            TProtocol protocol = new TJSONProtocol(tTransport);
            HelloWorldService.Client client = new HelloWorldService.Client(protocol);
            tTransport.open();
            String result = client.helloString(username);
            System.out.println("Thrify client result = " + result);
        } catch (TTransportException ex) {
            ex.printStackTrace();
        } catch (TException ex) {
            ex.printStackTrace();
        }finally {
            if(tTransport != null){
                tTransport.close();
            }
        }
    }
    public static void main(String[] args){
        HelloServiceClient client = new HelloServiceClient();
        client.startClient(" world");
    }
}
 (6)測試遠程調用

啟動服務端,日志如下:

啟動客戶端,日志如下:

調用成功,符合預期結果。

4.2 TThreadPoolServer 服務模型

線程池服務模型,使用標准的阻塞式IO,預先創建一組線程處理請求。

ThreadPoolHelloServiceServer.java

package org.wavemelody.thrift.demo;

import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;

/**
 * Created by Andy on 2018/8/14.
 */
public class ThreadPoolHelloServiceServer {
    public void startServer(){
        try {
            System.out.println("HelloWorldServer start ... ");
            TServerSocket serverTransport = new TServerSocket(8888);
            TThreadPoolServer.Args tArgs = new TThreadPoolServer.Args(serverTransport);
            TProcessor tProcessor = new HelloWorldService.Processor<HelloWorldService.Iface>(new HelloWorldServiceImpl());
            tArgs.processor(tProcessor);
            tArgs.protocolFactory(new TBinaryProtocol.Factory());
            // 線程池服務模型,使用標准的阻塞式IO,預先創建一組線程處理請求。
            TThreadPoolServer server = new TThreadPoolServer(tArgs);
            server.serve();
        } catch (TTransportException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args){
        ThreadPoolHelloServiceServer serviceServer = new ThreadPoolHelloServiceServer();
        serviceServer.startServer();
    }
}

客戶端和之前的代碼一樣,測試結果如下:

4.3  TNonblockingServer 服務模型

使用非阻塞式IO,服務端和客戶端需要指定 TFramedTransport 數據傳輸的方式。

服務端代碼 TNonblockingHelloServiceServer.java

package org.wavemelody.thrift.demo;

import org.apache.thrift.TMultiplexedProcessor;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.server.TNonblockingServer;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TNonblockingServerSocket;
import org.apache.thrift.transport.TTransportException;

/**
 * Created by Andy on 2018/8/14.
 */
public class TNonblockingHelloServiceServer {
    public void startServer(){
        try {
            System.out.println("HelloWorldServer start ... ");
            TNonblockingServerSocket tnbSocket = new TNonblockingServerSocket(8888);
            TNonblockingServer.Args tArgs = new TNonblockingServer.Args(tnbSocket);
            TProcessor tProcessor = new HelloWorldService.Processor<HelloWorldService.Iface>(new HelloWorldServiceImpl());
            tArgs.processor(tProcessor);
            tArgs.protocolFactory(new TBinaryProtocol.Factory());
            tArgs.transportFactory(new TFramedTransport.Factory());
            // 線程池服務模型,使用標准的阻塞式IO,預先創建一組線程處理請求。
            TNonblockingServer server = new TNonblockingServer(tArgs);
            server.serve();
        } catch (TTransportException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args){
        TNonblockingHelloServiceServer serviceServer = new TNonblockingHelloServiceServer();
        serviceServer.startServer();
    }
}

客戶端代碼:TNonblockingHelloServiceClient.java

package org.wavemelody.thrift.demo;

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;

/**
 * Created by Andy on 2018/8/14.
 */
public class TNonblockingHelloServiceClient {
    public void startClient(String username){
        TTransport tTransport = null;
        try {
            tTransport = new TFramedTransport(new TSocket("localhost",8888,30000));
            // 協議要和服務端一致
            TProtocol protocol = new TBinaryProtocol(tTransport);
//            TProtocol protocol = new TCompactProtocol(tTransport);
//            TProtocol protocol = new TJSONProtocol(tTransport);
            HelloWorldService.Client client = new HelloWorldService.Client(protocol);
            tTransport.open();
            String result = client.helloString(username);
            System.out.println("Thrify client result = " + result);
        } catch (TTransportException ex) {
            ex.printStackTrace();
        } catch (TException ex) {
            ex.printStackTrace();
        }finally {
            if(tTransport != null){
                tTransport.close();
            }
        }
    }
    public static void main(String[] args){
        TNonblockingHelloServiceClient client = new TNonblockingHelloServiceClient();
        client.startClient(" world");
    }
}

測試結果:

 


免責聲明!

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



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