Thrift是一個跨語言的服務部署框架,最初由Facebook於2007年開發,2008年進入Apache開源項目。Thrift經過IDL(Interface Definition Language,接口定義語言)來定義RPC(Remote Procedure Call,遠程過程調用)的接口和數據類型,而後經過thrift編譯器生成不一樣語言的代碼(目前支持C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),並由生成的代碼負責RPC協議層和傳輸層的實現。html
PS:CentOS下的Thrift的安裝流程能夠參考這裏。java
Thrift架構python
圖中,TProtocol(協議層),定義數據傳輸格式,例如:shell
TTransport(傳輸層),定義數據傳輸方式,能夠爲TCP/IP傳輸,內存共享或者文件共享等)被用做運行時庫。apache
Thrift支持的服務模型centos
Thrift其實是實現了C/S模式,經過代碼生成工具將thrift文生成服務器端和客戶端代碼(能夠爲不一樣語言),從而實現服務端和客戶端跨語言的支持。用戶在Thirft文件中聲明本身的服務,這些服務通過編譯後會生成相應語言的代碼文件,而後客戶端調用服務,服務器端提服務即可以了。數組
通常將服務放到一個.thrift文件中,服務的編寫語法與C語言語法基本一致,在.thrift文件中有主要有如下幾個內容:變量聲明(variable)、數據聲明(struct)和服務接口聲明(service, 能夠繼承其餘接口)。服務器
下面分析Thrift的tutorial中帶的例子tutorial.thrift:網絡
// 包含頭文件 include 「shared.thrift」 // 指定目標語言 namespace cpp tutorial // 定義變量 const i32 INT32CONSTANT = 9853 // 定義結構體 struct Work { 1: i32 num1 = 0, 2: i32 num2, 3: Operation op, 4: optional string comment, } // 定義服務 service Calculator extends shared.SharedService { /** * A method definition looks like C code. It has a return type, arguments, * and optionally a list of exceptions that it may throw. Note that argument * lists and exception lists are specified using the exact same syntax as * field lists in struct or exception definitions. */ void ping(), i32 add(1:i32 num1, 2:i32 num2), i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch), /** * This method has a oneway modifier. That means the client only makes * a request and does not listen for any response at all. Oneway methods * must be void. */ oneway void zip() }
編譯thrift文件,生成C++代碼:數據結構
./thrift --gen cpp tutorial.thrift #結果代碼存放在gen-cpp目錄下
若是是要生成java代碼:
./thrift --gen java tutorial.thrift #結果代碼存放在gen-java目錄下
client端和sever端代碼要調用編譯.thrift生成的中間文件。
下面分析cpp文件下面的CppClient.cpp和CppServer.cpp代碼
在client端,用戶自定義CalculatorClient類型的對象(用戶在.thrift文件中聲明的服務名稱是Calculator, 則生成的中間代碼中的主類爲CalculatorClient), 該對象中封裝了各類服務,能夠直接調用(如client.ping()), 而後thrift會經過封裝的rpc調用server端同名的函數。
在server端,須要實如今.thrift文件中聲明的服務中的全部功能,以便處理client發過來的請求。
Thrift文件支持shell命令,所以thrift是可執行的。
Thrfit支持shell註釋風格(#),也支持C/C++語言中單行(//)或者多行(/* */)註釋風格
一、基本類型
注意:thrift不支持無符號整型。
二、容器
注意:容器中的元素類型能夠是除了service 之外的任何合法thrift類型(包括結構體和異常)。
三、結構體 struct
Thrift結構體在概念上同C語言結構體類型—-一種將相關屬性彙集(封裝)在一塊兒的方式;
在面嚮對象語言中,thrift結構體被轉換成類。
struct Work { 1: i32 num1 = 0, 2: i32 num2, 3: Operation op, 4: optional string comment, }
結構體中,每一個字段包含一個整數ID,數據類型、字段名,和一個可選的默認值。
字段還能夠聲明爲"optional",當該字段沒有設置的時候,不會被序列化輸出;
規範的struct定義中的每一個域均會使用required或者optional關鍵字進行標識。若是required標識的域沒有賦值,thrift將給予提示。若是optional標識的域沒有賦值,該域將不會被序列化傳輸。若是某個optional標識域有缺省值而用戶沒有從新賦值,則該域的值一直爲缺省值。
四、異常 exception
異常在語法和功能上相似於結構體,只不過異常使用關鍵字exception而不是struct關鍵字聲明。但它在語義上不一樣於結構體,當定義一個RPC服務時,開發者可能須要聲明一個遠程方法拋出一個異常。
exception InvalidOperation { 1: i32 what, 2: string why }
五、服務 service
在流行的序列化/反序列化框架(如protocol buffer)中,Thrift是少有的提供多語言間RPC服務的框架。
Thrift編譯器會根據選擇的目標語言爲server產生服務接口代碼,爲client產生樁代碼。
//「Twitter」與「{」之間須要有空格!!! service Twitter { // 方法定義方式相似於C語言中的方式,它有一個返回值,一系列參數和可選的異常 // 列表. 注意,參數列表和異常列表定義方式與結構體中域定義方式一致. void ping(), // 函數定義可使用逗號或者分號標識結束 bool postTweet(1:Tweet tweet); // 參數能夠是基本類型或者結構體,參數是隻讀的(const),不能夠做爲返回值!!! TweetSearchResult searchTweets(1:string query); // 返回值能夠是基本類型或者結構體 // 」oneway」標識符表示client發出請求後沒必要等待回覆(非阻塞)直接進行下面的操做, // 」oneway」方法的返回值必須是void oneway void zip() // 返回值能夠是void }
service中的函數,其參數列表的定義方式與struct徹底同樣;
service支持繼承,一個service可以使用extends關鍵字繼承另外一個service,struct不支持繼承;
六、枚舉類型 enum
enum TweetType { TWEET, // 編譯器默認從1開始賦值 RETWEET = 2, // 能夠賦予某個常量某個整數 DM = 0xa, //容許常量是十六進制整數 REPLY // 末尾沒有逗號 }
struct Tweet { 1: required i32 userId; 2: required string userName; 3: required string text; 4: optional Location loc; 5: optional TweetType tweetType = TweetType.TWEET // 給常量賦缺省值時,使用常量的全稱 16: optional string language = "english" }
注意:枚舉常量必須是32位的正整數
七、常量 const
Thrift容許用戶定義常量,複雜的類型和結構體可以使用JSON形式表示。
const i32 INT_CONST = 1234; // 分號是可選的 const map<string,string> MAP_CONST = {"hello": "world", "goodnight": "moon"}
PS:跟C語言相似,Thrift也支持typedef語句,例如:
typedef i32 MyInteger
Thrift中的命名空間同C++中的namespace相似,它們均提供了一種組織(隔離)代碼的方式。由於每種語言均有本身的命名空間定義方式(如python中有module),thrift容許開發者針對特定語言定義namespace:
namespace cpp com.example.project namespace java com.example.project
下面介紹Thrift產生各類目標語言代碼的方式,
Thrift的網絡棧以下所示:
Transport層提供了一個簡單的網絡讀寫抽象層。這使得thrift底層的transport從系統其它部分(如:序列化/反序列化)解耦。
如下是一些Transport接口提供的方法:
open close read write listen accept flush
Protocol抽象層定義了一種將內存中數據結構映射成可傳輸格式的機制。換句話說,Protocol定義了datatype怎樣使用底層的Transport對本身進行編解碼。所以,Protocol的實現要給出編碼機制並負責對數據進行序列化。
Protocol接口的定義以下:
writeMessageBegin(name, type, seq) writeMessageEnd() writeStructBegin(name) writeStructEnd() writeFieldBegin(name, type, id) writeFieldEnd() writeFieldStop() writeMapBegin(ktype, vtype, size) writeMapEnd() writeListBegin(etype, size) writeListEnd() writeSetBegin(etype, size) writeSetEnd() writeBool(bool) writeByte(byte) writeI16(i16) writeI32(i32) writeI64(i64) writeDouble(double) writeString(string) name, type, seq = readMessageBegin() readMessageEnd() name = readStructBegin() readStructEnd() name, type, id = readFieldBegin() readFieldEnd() k, v, size = readMapBegin() readMapEnd() etype, size = readListBegin() readListEnd() etype, size = readSetBegin() readSetEnd() bool = readBool() byte = readByte() i16 = readI16() i32 = readI32() i64 = readI64() double = readDouble() string = readString()
Processor封裝了從輸入數據流中讀數據和向數據數據流中寫數據的操做。讀寫數據流用Protocol對象表示。Processor的結構體很是簡單:
interface TProcessor { bool process(TProtocol in, TProtocol out) throws TException }
與服務相關的processor實現由編譯器產生。Processor主要工做流程以下:從鏈接中讀取數據(使用輸入protocol),將處理受權給handler(由用戶實現),最後將結果寫到鏈接上(使用輸出protocol)。
Server將以上全部特性集成在一塊兒:
(1) 建立一個transport對象
(2) 爲transport對象建立輸入輸出protocol
(3) 基於輸入輸出protocol建立processor
(4) 等待鏈接請求並將之交給processor處理
原文連接:https://www.cnblogs.com/chenny7/p/4224720.html
參考文檔:
http://dongxicheng.org/search-engine/thrift-framework-intro/
http://dongxicheng.org/search-engine/thrift-guide/
http://dongxicheng.org/search-engine/thrift-internals/
http://dongxicheng.org/search-engine/thrift-bidirectional-async-rpc/
Thrift是一個跨語言的服務部署框架,最初由Facebook於2007年開發,2008年進入Apache開源項目。Thrift經過IDL(Interface Definition Language,接口定義語言)來定義RPC(Remote Procedure Call,遠程過程調用)的接口和數據類型,而後經過thrift編譯器生成不一樣語言的代碼(目前支持C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),並由生成的代碼負責RPC協議層和傳輸層的實現。
PS:CentOS下的Thrift的安裝流程能夠參考這裏。
Thrift架構
圖中,TProtocol(協議層),定義數據傳輸格式,例如:
TTransport(傳輸層),定義數據傳輸方式,能夠爲TCP/IP傳輸,內存共享或者文件共享等)被用做運行時庫。
Thrift支持的服務模型
Thrift其實是實現了C/S模式,經過代碼生成工具將thrift文生成服務器端和客戶端代碼(能夠爲不一樣語言),從而實現服務端和客戶端跨語言的支持。用戶在Thirft文件中聲明本身的服務,這些服務通過編譯後會生成相應語言的代碼文件,而後客戶端調用服務,服務器端提服務即可以了。
通常將服務放到一個.thrift文件中,服務的編寫語法與C語言語法基本一致,在.thrift文件中有主要有如下幾個內容:變量聲明(variable)、數據聲明(struct)和服務接口聲明(service, 能夠繼承其餘接口)。
下面分析Thrift的tutorial中帶的例子tutorial.thrift:
// 包含頭文件 include 「shared.thrift」 // 指定目標語言 namespace cpp tutorial // 定義變量 const i32 INT32CONSTANT = 9853 // 定義結構體 struct Work { 1: i32 num1 = 0, 2: i32 num2, 3: Operation op, 4: optional string comment, } // 定義服務 service Calculator extends shared.SharedService { /** * A method definition looks like C code. It has a return type, arguments, * and optionally a list of exceptions that it may throw. Note that argument * lists and exception lists are specified using the exact same syntax as * field lists in struct or exception definitions. */ void ping(), i32 add(1:i32 num1, 2:i32 num2), i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch), /** * This method has a oneway modifier. That means the client only makes * a request and does not listen for any response at all. Oneway methods * must be void. */ oneway void zip() }
編譯thrift文件,生成C++代碼:
./thrift --gen cpp tutorial.thrift #結果代碼存放在gen-cpp目錄下
若是是要生成java代碼:
./thrift --gen java tutorial.thrift #結果代碼存放在gen-java目錄下
client端和sever端代碼要調用編譯.thrift生成的中間文件。
下面分析cpp文件下面的CppClient.cpp和CppServer.cpp代碼
在client端,用戶自定義CalculatorClient類型的對象(用戶在.thrift文件中聲明的服務名稱是Calculator, 則生成的中間代碼中的主類爲CalculatorClient), 該對象中封裝了各類服務,能夠直接調用(如client.ping()), 而後thrift會經過封裝的rpc調用server端同名的函數。
在server端,須要實如今.thrift文件中聲明的服務中的全部功能,以便處理client發過來的請求。
Thrift文件支持shell命令,所以thrift是可執行的。
Thrfit支持shell註釋風格(#),也支持C/C++語言中單行(//)或者多行(/* */)註釋風格
一、基本類型
注意:thrift不支持無符號整型。
二、容器
注意:容器中的元素類型能夠是除了service 之外的任何合法thrift類型(包括結構體和異常)。
三、結構體 struct
Thrift結構體在概念上同C語言結構體類型—-一種將相關屬性彙集(封裝)在一塊兒的方式;
在面嚮對象語言中,thrift結構體被轉換成類。
struct Work { 1: i32 num1 = 0, 2: i32 num2, 3: Operation op, 4: optional string comment, }
結構體中,每一個字段包含一個整數ID,數據類型、字段名,和一個可選的默認值。
字段還能夠聲明爲"optional",當該字段沒有設置的時候,不會被序列化輸出;
規範的struct定義中的每一個域均會使用required或者optional關鍵字進行標識。若是required標識的域沒有賦值,thrift將給予提示。若是optional標識的域沒有賦值,該域將不會被序列化傳輸。若是某個optional標識域有缺省值而用戶沒有從新賦值,則該域的值一直爲缺省值。
四、異常 exception
異常在語法和功能上相似於結構體,只不過異常使用關鍵字exception而不是struct關鍵字聲明。但它在語義上不一樣於結構體,當定義一個RPC服務時,開發者可能須要聲明一個遠程方法拋出一個異常。
exception InvalidOperation { 1: i32 what, 2: string why }
五、服務 service
在流行的序列化/反序列化框架(如protocol buffer)中,Thrift是少有的提供多語言間RPC服務的框架。
Thrift編譯器會根據選擇的目標語言爲server產生服務接口代碼,爲client產生樁代碼。
//「Twitter」與「{」之間須要有空格!!! service Twitter { // 方法定義方式相似於C語言中的方式,它有一個返回值,一系列參數和可選的異常 // 列表. 注意,參數列表和異常列表定義方式與結構體中域定義方式一致. void ping(), // 函數定義可使用逗號或者分號標識結束 bool postTweet(1:Tweet tweet); // 參數能夠是基本類型或者結構體,參數是隻讀的(const),不能夠做爲返回值!!! TweetSearchResult searchTweets(1:string query); // 返回值能夠是基本類型或者結構體 // 」oneway」標識符表示client發出請求後沒必要等待回覆(非阻塞)直接進行下面的操做, // 」oneway」方法的返回值必須是void oneway void zip() // 返回值能夠是void }
service中的函數,其參數列表的定義方式與struct徹底同樣;
service支持繼承,一個service可以使用extends關鍵字繼承另外一個service,struct不支持繼承;
六、枚舉類型 enum
enum TweetType { TWEET, // 編譯器默認從1開始賦值 RETWEET = 2, // 能夠賦予某個常量某個整數 DM = 0xa, //容許常量是十六進制整數 REPLY // 末尾沒有逗號 }
struct Tweet { 1: required i32 userId; 2: required string userName; 3: required string text; 4: optional Location loc; 5: optional TweetType tweetType = TweetType.TWEET // 給常量賦缺省值時,使用常量的全稱 16: optional string language = "english" }
注意:枚舉常量必須是32位的正整數
七、常量 const
Thrift容許用戶定義常量,複雜的類型和結構體可以使用JSON形式表示。
const i32 INT_CONST = 1234; // 分號是可選的 const map<string,string> MAP_CONST = {"hello": "world", "goodnight": "moon"}
PS:跟C語言相似,Thrift也支持typedef語句,例如:
typedef i32 MyInteger
Thrift中的命名空間同C++中的namespace相似,它們均提供了一種組織(隔離)代碼的方式。由於每種語言均有本身的命名空間定義方式(如python中有module),thrift容許開發者針對特定語言定義namespace:
namespace cpp com.example.project namespace java com.example.project
下面介紹Thrift產生各類目標語言代碼的方式,
Thrift的網絡棧以下所示:
Transport層提供了一個簡單的網絡讀寫抽象層。這使得thrift底層的transport從系統其它部分(如:序列化/反序列化)解耦。
如下是一些Transport接口提供的方法:
open
close
read
write
listen
accept
flush
Protocol抽象層定義了一種將內存中數據結構映射成可傳輸格式的機制。換句話說,Protocol定義了datatype怎樣使用底層的Transport對本身進行編解碼。所以,Protocol的實現要給出編碼機制並負責對數據進行序列化。
Protocol接口的定義以下:
writeMessageBegin(name, type, seq) writeMessageEnd() writeStructBegin(name) writeStructEnd() writeFieldBegin(name, type, id) writeFieldEnd() writeFieldStop() writeMapBegin(ktype, vtype, size) writeMapEnd() writeListBegin(etype, size) writeListEnd() writeSetBegin(etype, size) writeSetEnd() writeBool(bool) writeByte(byte) writeI16(i16) writeI32(i32) writeI64(i64) writeDouble(double) writeString(string) name, type, seq = readMessageBegin() readMessageEnd() name = readStructBegin() readStructEnd() name, type, id = readFieldBegin() readFieldEnd() k, v, size = readMapBegin() readMapEnd() etype, size = readListBegin() readListEnd() etype, size = readSetBegin() readSetEnd() bool = readBool() byte = readByte() i16 = readI16() i32 = readI32() i64 = readI64() double = readDouble() string = readString()
Processor封裝了從輸入數據流中讀數據和向數據數據流中寫數據的操做。讀寫數據流用Protocol對象表示。Processor的結構體很是簡單:
interface TProcessor { bool process(TProtocol in, TProtocol out) throws TException }
與服務相關的processor實現由編譯器產生。Processor主要工做流程以下:從鏈接中讀取數據(使用輸入protocol),將處理受權給handler(由用戶實現),最後將結果寫到鏈接上(使用輸出protocol)。
Server將以上全部特性集成在一塊兒:
(1) 建立一個transport對象
(2) 爲transport對象建立輸入輸出protocol
(3) 基於輸入輸出protocol建立processor
(4) 等待鏈接請求並將之交給processor處理
參考文檔:
http://dongxicheng.org/search-engine/thrift-framework-intro/
http://dongxicheng.org/search-engine/thrift-guide/
http://dongxicheng.org/search-engine/thrift-internals/
http://dongxicheng.org/search-engine/thrift-bidirectional-async-rpc/