2017-01-19 16:47:57html
首先經過先面兩個示例簡單感覺一下Thrift(RPC)服務端與客戶端之間的通訊......java
RPC學習----Thrift快速入門和Java簡單示例apache
Thrift 源於大名鼎鼎的 facebook 之手,在 2007 年 facebook 提交 Apache 基金會將 Thrift 做爲一個開源項目,對於當時的 facebook 來講創造 thrift 是爲了解決 facebook 系統中各系統間大數據量的傳 輸通訊以及系統之間語言環境不一樣須要跨平臺的特性。因此 thrift 能夠支持多種程序語言,例如: C++, C#, Cocoa, Erlang, Haskell, Java, Ocami, Perl, PHP, Python, Ruby, Smalltalk. 在多種不一樣的語言之間通訊 thrift能夠做爲二進制的高性能的通信中間件,支持數據(對象)序列化和多種類型的 RPC 服 務。Thrift 適用於程序對程 序靜態的數據交換,須要先肯定好他的數據結構,他是徹底靜態化的,當數據結構發生變化時,必須從新編輯 IDL 文件,代碼生成,再編譯載入的流程,跟其餘 IDL 工具相比較能夠視爲是 Thrift 的弱項,Thrift 適用於搭建大型數據交換及存儲的通用工具,對於大型系統中的內部數據傳輸相對於 JSON 和 xml 不管在性能、傳輸大小上有明顯的優點。數據結構
Thrift 是 IDL(interface definition language)描述性語言的一個具體實現,關於 IDL的話題咱們能夠追溯到 CORBA 盛行 1999-2001 年(Common Object Request Broker Architecture/公用對象請求代理體系結構),在 IDL 中咱們彷佛不會忘記到這幾個關鍵字:module、interface、string、long 和 int,我還記得 IDL 利用 module來建立名稱空間,而且準確地映射爲 Java 的 package,這些特性幾乎和如今 thrift的特性徹底相同,因此 thrift 的設計思想和理念毫不是什麼從火星來的 new idea,看看在那個 CORBA 盛行的年代人們提出的概念,如圖所示 CORBA 請求的各個部分,回頭咱們再與 thrift 進行對比一下:多線程
Thrift 是一個服務端和客戶端的架構體系,從我我的的感官上來看 Thrift 是一個相似XML-RPC+Java-to- IDL+Serialization Tools=Thrift 的東東,Thrift 具備本身內部 定義的傳輸協議規範(TProtocol)和傳輸數據標準(TTransports),經過 IDL 腳本對傳輸數據的數據結構(struct) 和傳輸數據的業務邏輯(service)根據不一樣的運行環境快速的 構建相應的代碼,而且經過本身內部的序列化機制對傳輸的數據進行簡化和壓縮提升高併發、 大型系統中數據交互的成本,下圖描繪了 Thrift 的總體架構,分爲 6 個部分:架構
你的業務邏輯實現(Your Code)
客戶端和服務端對應的 Service
執行讀寫操做的計算結果
TProtocol
TTransports
底層 I/O 通訊
圖中前面 3 個部分是 1.你經過 Thrift 腳本文件生成的代碼,2.圖中的褐色框部分是你根據生成代碼構建的客戶端和處理器的代碼,3.圖中紅色的部分是 2 端產生的計算結 果。從 TProtocol 下面 3 個部分是 Thrift 的傳輸體系和傳輸協議以及底層 I/O 通訊,Thrift 而且提供 堵塞、非阻塞,單線程、多線程的模式運行在服務器上,還能夠配合 服務器/容器一塊兒運行,能夠和現有 JEE 服務器/Web 容器無縫的結合。併發
bool:布爾值,true 或 false,對應 Java 的 boolean
byte:8 位有符號整數,對應 Java 的 byte
i16:16 位有符號整數,對應 Java 的 short
i32:32 位有符號整數,對應 Java 的 int
i64:64 位有符號整數,對應 Java 的 long
double:64 位浮點數,對應 Java 的 double
string:utf-8編碼的字符串,對應 Java 的 String
struct:定義公共的對象,相似於 C 語言中的結構體定義,在 Java 中是一個 JavaBean
list:對應 Java 的 ArrayList
set:對應 Java 的 HashSet
map:對應 Java 的 HashMap
exception:對應 Java 的 Exception
service:對應服務的類
Thrift 可讓你選擇客戶端與服務端之間傳輸通訊協議的類別,在傳輸協議上整體上劃分爲文本(text)和二進制(binary)傳輸協議, 爲節約帶寬,提供傳輸效率,通常狀況下 使用二進制類型的傳輸協議爲多數,但有時會仍是會使用基於文本類型的協議,這須要根據項目/產品中的實際需求。ide
TBinaryProtocol–二進制編碼格式進行數據傳輸
TCompactProtocol–這種協議很是有效的,使用 Variable-Length Quantity(VLQ) 編碼對數據進行壓縮
TJSONProtocol–使用 JSON 的數據編碼協議進行數據傳輸
TSimpleJSONProtocol–這種節約只提供 JSON 只寫的協議,適用於經過腳本語言解析
TDebugProtocol–在開發的過程當中幫助開發人員調試用的,以文本的形式展示方便閱讀
TSocket-使用堵塞式 I/O 進行傳輸,也是最多見的模式
TFramedTransport-使用非阻塞方式,按塊的大小,進行傳輸,相似於 Java 中的 NIO
TFileTransport-顧名思義按照文件的方式進程傳輸,雖然這種方式不提供 Java 的實現,可是實現起來很是簡單
TMemoryTransport-使用內存 I/O,就比如 Java 中的 ByteArrayOutputStream實現
TZlibTransport- 使用執行 zlib 壓縮,不提供 Java 的實現
TSimpleServer-單線程服務器端使用標準的堵塞式 I/O
TThreadPoolServer-多線程服務器端使用標準的堵塞式 I/O
TNonblockingServer–多線程服務器端使用非堵塞式 I/O,而且實現了 Java 中的 NIO 通道
XML 與 JSON 相比體積太大,可是 XML 傳統,也不算複雜。JSON 體積較小,新穎,但不夠完善。Thrift 體積超小,使用起來比較麻煩,不如前二者輕便,可是對於 1.高併發、2.數據傳 輸量大、3.多語言環境, 知足其中 2 點使用 thrift 仍是值得的。高併發
實現服務處理接口impl
建立TProcessor
建立TServerTransport
建立TProtocol
建立TServer
啓動Server
建立TTransport
建立TProtocol
基於TTransport和TProtocol建立 Client
調用Client的相應方法
tips:客戶端和服務端的協議要一致
新建文件並命名爲demoHello.thrift
1 namespace java com.unionpay.thrifttest 2 3 service HelloWorldService{ 4 string sayHello(1:string username) 5 }
1 thrift -r -gen java demoHello.thrift
1 import org.apache.thrift.protocol.TCompactProtocol; 2 import org.apache.thrift.server.TServer; 3 import org.apache.thrift.server.TSimpleServer; 4 import org.apache.thrift.transport.TServerSocket; 5 import org.apache.thrift.transport.TServerTransport; 6 7 public class HelloServerDemo { 8 9 //定義服務端口號 10 public static final int SERVER_PORT = 8090; 11 12 public static void main(String[] args){ 13 HelloServerDemo service = new HelloServerDemo(); 14 service.startServer(); 15 } 16 17 public void startServer(){ 18 try{ 19 System.out.println("HelloWorld TSimpleServer start..."); 20 21 /* thrift Processor 業務邏輯處理層 22 建立Processor,HelloWorldImpl 實現類做爲參數傳入Processor構造方法裏 23 processor主要完成的事情: 24 1.把idl裏定義的方法進行封裝,最終暴露出一個統一的接口給thrift server進行調用 25 2.封裝protocol和transport層,包括輸入輸出流的處理細節、序列化反序列化*/ 26 HelloWorldService.Processor<HelloWorldService.Iface> tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(new HelloWorldImpl()); 27 28 //建立TServerTransport 29 TServerTransport serverTransport = new TServerSocket(SERVER_PORT); 30 TServer.Args tArgs = new TServer.Args(serverTransport); 31 tArgs.processor(tprocessor); 32 //建立TProtocol 33 tArgs.protocolFactory(new TCompactProtocol.Factory()); 34 //建立TServer 35 TServer server = new TSimpleServer(tArgs); 36 //啓動TServer 37 server.serve(); 38 }catch(Exception e){ 39 System.out.println("Server start error!"); 40 e.printStackTrace(); 41 } 42 } 43 }
1 import org.apache.thrift.TException; 2 import org.apache.thrift.protocol.TCompactProtocol; 3 import org.apache.thrift.protocol.TProtocol; 4 import org.apache.thrift.transport.TSocket; 5 import org.apache.thrift.transport.TTransport; 6 import org.apache.thrift.transport.TTransportException; 7 8 /** 9 * @author jxwch 10 * @date 2017.01.17 11 * 12 */ 13 public class HelloClientDemo { 14 15 //定義Socket服務參數 16 public static final String SERVER_IP = "localhost"; 17 public static final int SERVER_PORT = 8090; 18 public static final int TIMEOUT = 30000; 19 20 21 public static void main(String[] args){ 22 HelloClientDemo client = new HelloClientDemo(); 23 client.startClient("jxwch"); 24 } 25 26 public void startClient(String userName){ 27 28 29 TTransport transport = null; 30 try{ 31 //建立TTransport 32 transport = new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT); 33 //建立TProtocol 34 TProtocol protocol = new TCompactProtocol(transport); 35 //建立Client 36 HelloWorldService.Client client = new HelloWorldService.Client(protocol); 37 //啓動TTransport 38 transport.open(); 39 40 //調用client中封裝的方法 41 String result = client.sayHello(userName); 42 System.out.println("Thrift Client result: " + result); 43 }catch(TTransportException e){ 44 e.printStackTrace(); 45 }catch(TException e){ 46 e.printStackTrace(); 47 }finally{ 48 if(null != transport){ 49 transport.close(); 50 } 51 } 52 } 53 }