日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Thrift使用指南

發布時間:2024/4/17 编程问答 66 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Thrift使用指南 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?http://dongxicheng.org/search-engine/thrift-guide/

1. 內容概要

本文檔比較全面的介紹了thrift(關于thrift框架的介紹,參考我這篇文章:Thrift框架介紹)語法,代碼生成結構和應用經驗。本文主要講述的對象是thrift文件,并未涉及其client和server的編寫方法(關于client和server的編寫方法,可參考我這篇文章:使用Thrift RPC編寫程序)。

本文檔大部分內容翻譯自文章:“Thrift:The missing Guide“。

2. 語法參考

2.1 Types

Thrift類型系統包括預定義基本類型,用戶自定義結構體,容器類型,異常和服務定義

(1) 基本類型

1 2 3 4 5 6 7 8 9 10 11 12 13 14 bool:布爾類型(true or value),占一個字節 ?? byte:有符號字節 ?? i16:16位有符號整型 ?? i32:32位有符號整型 ?? i64:64位有符號整型 ?? double:64位浮點數 ?? string:未知編碼或者二進制的字符串

注意,thrift不支持無符號整型,因為很多目標語言不存在無符號整型(如java)。

(2) 容器類型

Thrift容器與類型密切相關,它與當前流行編程語言提供的容器類型相對應,采用java泛型風格表示的。Thrift提供了3種容器類型:

List<t1>:一系列t1類型的元素組成的有序表,元素可以重復

Set<t1>:一系列t1類型的元素組成的無序表,元素唯一

Map<t1,t2>:key/value對(key的類型是t1且key唯一,value類型是t2)。

容器中的元素類型可以是除了service意外的任何合法thrift類型(包括結構體和異常)。

(3)? 結構體和異常

Thrift結構體在概念上同C語言結構體類型—-一種將相關屬性聚集(封裝)在一起的方式。在面向對象語言中,thrift結構體被轉換成類。

異常在語法和功能上類似于結構體,只不過異常使用關鍵字exception而不是struct關鍵字聲明。但它在語義上不同于結構體—當定義一個RPC服務時,開發者可能需要聲明一個遠程方法拋出一個異常。

結構體和異常的聲明將在下一節介紹。

(4)? 服務

服務的定義方法在語法上等同于面向對象語言中定義接口。Thrift編譯器會產生實現這些接口的client和server樁。具體參見下一節。

(5)? 類型定義

Thrift支持C/C++風格的typedef:

1 2 3 4 typedef i32 MyInteger?? \\a ?? typedef Tweet ReTweet? \\b

說明:

a.? 末尾沒有逗號

b.?? struct可以使用typedef

2.2?? 枚舉類型

可以像C/C++那樣定義枚舉類型,如:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 enum TweetType { ?? TWEET,?????? //a ?? RETWEET = 2, //b ?? DM = 0xa,? //c ?? REPLY ?? }??????? //d ?? struct Tweet { ?? 1: required i32 userId; ?? 2: required string userName; ?? 3: required string text; ?? 4: optional Location loc; ?? 5: optional TweetType tweetType = TweetType.TWEET // e ?? 16: optional string language = "english" ?? }

說明:

a.? 編譯器默認從0開始賦值

b.? 可以賦予某個常量某個整數

c.? 允許常量是十六進制整數

d.? 末尾沒有逗號

e.? 給常量賦缺省值時,使用常量的全稱

注意,不同于protocol buffer,thrift不支持枚舉類嵌套,枚舉常量必須是32位的正整數

2.3?? 注釋

Thrfit支持shell注釋風格,C/C++語言中單行或者多行注釋風格

1 2 3 4 5 6 7 8 9 10 11 12 # This is a valid comment. ?? /* ?? * This is a multi-line comment. ?? * Just like in C. ?? */ ?? // C++/Java style single-line comments work just as well.

2.4?? 命名空間

Thrift中的命名空間同C++中的namespace和java中的package類似,它們均提供了一種組織(隔離)代碼的方式。因為每種語言均有自己的命名空間定義方式(如python中有module),thrift允許開發者針對特定語言定義namespace:

1 2 3 4 namespace cpp com.example.project? // a ?? namespace java com.example.project // b

說明:

a.? 轉化成namespace com { namespace example { namespace project {

b.? 轉換成package com.example.project

2.5?? 文件包含

Thrift允許thrift文件包含,用戶需要使用thrift文件名作為前綴訪問被包含的對象,如:

1 2 3 4 5 6 7 8 9 10 include "tweet.thrift"?????????? // a ?? ... ?? struct TweetSearchResult { ?? 1: list<tweet.Tweet> tweets; // b ?? }

說明:

a.? thrift文件名要用雙引號包含,末尾沒有逗號或者分號

b.? 注意tweet前綴

2.6?? 常量

Thrift允許用戶定義常量,復雜的類型和結構體可使用JSON形式表示。

1 2 3 4 const i32 INT_CONST = 1234;??? // a ?? const map<string,string> MAP_CONST = {"hello": "world", "goodnight": "moon"}

說明:

a.? 分號是可選的,可有可無;支持十六進制賦值。

2.7?? 定義結構體

結構體由一系列域組成,每個域有唯一整數標識符,類型,名字和可選的缺省參數組成。如:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 struct Tweet { ?? 1: required i32 userId;????????????????? // a ?? 2: required string userName;???????????? // b ?? 3: required string text; ?? 4: optional Location loc;??????????????? // c ?? 16: optional string language = "english" // d ?? } ?? struct Location {??????????????????????????? // e ?? 1: required double latitude; ?? 2: required double longitude; ?? }

說明:

a.? 每個域有一個唯一的,正整數標識符

b.? 每個域可以標識為required或者optional(也可以不注明)

c.? 結構體可以包含其他結構體

d.? 域可以有缺省值

e.? 一個thrift中可定義多個結構體,并存在引用關系

規范的struct定義中的每個域均會使用required或者optional關鍵字進行標識。如果required標識的域沒有賦值,thrift將給予提示。如果optional標識的域沒有賦值,該域將不會被序列化傳輸。如果某個optional標識域有缺省值而用戶沒有重新賦值,則該域的值一直為缺省值。

與service不同,結構體不支持繼承,即,一個結構體不能繼承另一個結構體。

2.8?? 定義服務

在流行的序列化/反序列化框架(如protocol buffer)中,thrift是少有的提供多語言間RPC服務的框架。

Thrift編譯器會根據選擇的目標語言為server產生服務接口代碼,為client產生樁代碼。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 //“Twitter”與“{”之間需要有空格!!! service Twitter { ?? // 方法定義方式類似于C語言中的方式,它有一個返回值,一系列參數和可選的異常 ?? // 列表. 注意,參數列表和異常列表定義方式與結構體中域定義方式一致. ?? void ping(),??????????????????????????????????? // a ?? bool postTweet(1:Tweet tweet);????????????????? // b ?? TweetSearchResult searchTweets(1:string query); // c ?? // ”oneway”標識符表示client發出請求后不必等待回復(非阻塞)直接進行下面的操作, ?? // ”oneway”方法的返回值必須是void ?? oneway void zip()?????????????????????????????? // d ?? }

說明:

a. 函數定義可以使用逗號或者分號標識結束

b. 參數可以是基本類型或者結構體,參數是只讀的(const),不可以作為返回值!!!

c. 返回值可以是基本類型或者結構體

d. 返回值可以是void

注意,函數中參數列表的定義方式與struct完全一樣

Service支持繼承,一個service可使用extends關鍵字繼承另一個service

3.? 產生代碼

本節介紹thrift產生各種目標語言代碼的方式。本節從幾個基本概念開始,逐步引導開發者了解產生的代碼是怎么樣組織的,進而幫助開發者更快地明白thrift的使用方法。

概念

Thrift的網絡棧如下所示:

3.1?? Transport

Transport層提供了一個簡單的網絡讀寫抽象層。這使得thrift底層的transport從系統其它部分(如:序列化/反序列化)解耦。以下是一些Transport接口提供的方法:

1 2 3 4 5 6 7 8 9 10 open ?? close ?? read ?? write ?? flush

除了以上幾個接口,Thrift使用ServerTransport接口接受或者創建原始transport對象。正如名字暗示的那樣,ServerTransport用在server端,為到來的連接創建Transport對象。

1 2 3 4 5 6 7 8 open ?? listen ?? accept ?? close

3.2?? Protocol

Protocol抽象層定義了一種將內存中數據結構映射成可傳輸格式的機制。換句話說,Protocol定義了datatype怎樣使用底層的Transport對自己進行編解碼。因此,Protocol的實現要給出編碼機制并負責對數據進行序列化。

Protocol接口的定義如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 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()

下面是一些對大部分thrift支持的語言均可用的protocol:

(1)???? binary:簡單的二進制編碼

(2)???? Compact:具體見THRIFT-11

(3)???? Json

3.3?? Processor

Processor封裝了從輸入數據流中讀數據和向數據數據流中寫數據的操作。讀寫數據流用Protocol對象表示。Processor的結構體非常簡單:

1 2 3 4 5 6 interface TProcessor { ?? bool process(TProtocol in, TProtocol out) throws TException ?? }

與服務相關的processor實現由編譯器產生。Processor主要工作流程如下:從連接中讀取數據(使用輸入protocol),將處理授權給handler(由用戶實現),最后將結果寫到連接上(使用輸出protocol)。

3.4?? Server

Server將以上所有特性集成在一起:

(1)? 創建一個transport對象

(2)? 為transport對象創建輸入輸出protocol

(3)? 基于輸入輸出protocol創建processor

(4)? 等待連接請求并將之交給processor處理

3.5?? 應用舉例

下面,我們討論thrift文件產生的特定語言代碼。下面給出thrift文件描述:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 namespace cpp thrift.example ?? namespace java thrift.example ?? enum TweetType { ?? TWEET, ?? RETWEET = 2, ?? DM = 0xa, ?? REPLY ?? } ?? struct Location { ?? 1: required double latitude; ?? 2: required double longitude; ?? } ?? 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"; ?? } ?? typedef list<Tweet> TweetList ?? struct TweetSearchResult { ?? 1: TweetList tweets; ?? } ?? const i32 MAX_RESULTS = 100; ?? service Twitter { ?? void ping(), ?? bool postTweet(1:Tweet tweet); ?? TweetSearchResult searchTweets(1:string query); ?? oneway void zip() ?? }

(1) Java語言

(a)? 產生的文件

一個單獨的文件(Constants.java)包含所有的常量定義。

每個結構體,枚舉或者服務各占一個文件

$ tree gen-java

`– thrift

`– example

|– Constants.java

|– Location.java

|– Tweet.java

|– TweetSearchResult.java

|– TweetType.java

`– Twitter.java

(b)? 類型

thrift將各種基本類型和容器類型映射成java類型:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 bool: boolean ?? byte: byte ?? i16: short ?? i32: int ?? i64: long ?? double: double ?? string: String ?? list<t1>: List<t1> ?? set<t1>: Set<t1> ?? map<t1,t2>: Map<t1, t2>

(c)? typedef

Java不支持typedef,它只使用原始類型,如,在上面的例子中,產生的代碼中,TweetSearchResult會被還原成list<Tweet> tweets

(d)? Enum

Thrift直接將枚舉類型映射成java的枚舉類型。用戶可以使用geValue方法獲取枚舉常量的值。此外,編譯器會產生一個findByValue方法獲取枚舉對應的數值。

(e)? 常量

Thrift把所有的常量放在一個叫Constants的public類中,每個常量修飾符是public static final。

(2)? C++語言

(a)? 產生的文件

所有變量均存放在一個.cpp/.h文件對中

所有的類型定義(枚舉或者結構體)存放到另一個.cpp/.h文件對中

每一個service有自己的.cpp/.h文件

$ tree gen-cpp

|– example_constants.cpp

|– example_constants.h

|– example_types.cpp

|– example_types.h

|– Twitter.cpp

|– Twitter.h

`– Twitter_server.skeleton.cpp

其他語言

Python,Ruby,javascript等

4.? 實踐經驗

thrift文件內容可能會隨著時間變化的。如果已經存在的消息類型不再符合設計要求,比如,新的設計要在message格式中添加一個額外字段,但你仍想使用以前的thrift文件產生的處理代碼。如果想要達到這個目的,只需:

(1)? 不要修改已存在域的整數編號

(2)? 新添加的域必須是optional的,以便格式兼容。對于一些語言,如果要為optional的字段賦值,需要特殊處理,比如對于C++語言,要為

1 2 3 4 5 6 7 8 9 10 struct Example{ ?? 1 : i32 id, ?? 2 : string name, ?? 3 : optional age, ?? }

中的optional字段age賦值,需要將它的__isset值設為true,這樣才能序列化并傳輸或者存儲(不然optional字段被認為不存在,不會被傳輸或者存儲),

如:

1 2 3 4 5 6 7 8 9 10 Example example; ?? ...... ?? example.age=10, ?? example.__isset.age = true; //__isset是每個thrift對象的自帶的public成員,來指定optional字段是否啟用并賦值。 ?? ......

(3)? 非required域可以刪除,前提是它的整數編號不會被其他域使用。對于刪除的字段,名字前面可添加“OBSOLETE_”以防止其他字段使用它的整數編號。

(4) thrift文件應該是unix格式的(windows下的換行符與unix不同,可能會導致你的程序編譯不過),如果是在window下編寫的,可使用dos2unix轉化為unix格式。

(5)? 貌似當前的thrift版本(0.6.1)不支持常量表達式的定義(如 const i32 DAY = 24 * 60 * 60),這可能是考慮到不同語言,運算符不盡相同。

原創文章,轉載請注明: 轉載自董的博客

?

總結

以上是生活随笔為你收集整理的Thrift使用指南的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。