協議和編譯碼是乙個網路應用程式的核心問題之一,客戶端和伺服器通過約定的協議來傳輸訊息(資料),通過特定的格式來編譯碼字節流,並轉化成業務訊息,提供給上層框架呼叫。
thrift的協議比較簡單,它把協議和編譯碼整合在了一起。抽象類tprotocol定義了協議和編譯碼的頂層介面。個人感覺採用抽象類而不是介面的方式來定義頂層介面並不好,tprotocol關聯了乙個ttransport傳輸物件,而不是提供乙個類似gettransport()的介面,導致抽象類的擴充套件性比介面差。
tprotocol主要做了兩個事情:
1. 關聯ttransport物件
2.定義一系列讀寫訊息的編譯碼介面,包括兩類,一類是複雜資料結構比如readmessagebegin, readmessageend, writemessagebegin, writmessageend.還有一類是基本資料結構,比如readi32, writei32, readstring, writestring
public abstract class tprotocol
/*** scheme accessor
*/public class extends ischeme> getscheme()
}
所謂協議就是客戶端和伺服器端約定傳輸什麼資料,如何解析傳輸的資料。對於乙個rpc呼叫的協議來說,要傳輸的資料主要有:
呼叫方1. 方法的名稱,包括類的名稱和方法的名稱
2. 方法的引數,包括型別和引數值
3.一些附加的資料,比如附件,超時事件,自定義的控制資訊等等
返回方1. 呼叫的返回碼
2. 返回值
3.異常資訊
從tprotocol的定義我們可以看出thrift的協議約定如下事情:
1.先writemessagebegin表示開始傳輸訊息了,寫訊息頭。message裡面定義了方法名,呼叫的型別,版本號,訊息seqid
2.接下來是寫方法的引數,實際就是寫訊息體。如果引數是乙個類,就writestructbegin
3. 接下來寫字段,writefieldbegin, 這個方法會寫接下來的字段的資料型別和順序號。這個順序號是thrfit對要傳輸的字段的乙個編碼,從1開始
4. 如果是乙個集合就writelistbegin/writemapbegin,如果是乙個基本資料型別,比如int, 就直接writei32
5. 每個複雜資料型別寫完都呼叫write***end,直到writemessageend結束
6. 讀訊息時根據資料型別讀取相應的長度
每個write***都是採用訊息頭+訊息體的方式。我們來看tbinaryprotocol的實現。
1.writemessgebegin方法寫了訊息頭,包括4位元組的版本號和型別資訊,字串型別的方法名,4位元組的序列號seqid
2. writefieldbegin,寫了1個位元組的字段資料型別,和2個位元組欄位的順序號
3. writei32,寫了4個位元組的位元組陣列
4. writestring,先寫4位元組訊息頭表示字串長度,再寫字串位元組
5. writebinary,先寫4位元組訊息頭表示位元組陣列長度,再寫位元組陣列內容
6.readmessagebegin時,先讀4位元組版本和型別資訊,再讀字串,再讀4位元組序列號
7.readfieldbegin,先讀1個位元組的字段資料型別,再讀2個位元組的字段順序號
8. readstring時,先讀4位元組字串長度,再讀字串內容。字串統一採用utf-8編碼
public void writemessagebegin(tmessage message) throws texception else
}public void writefieldbegin(tfield field) throws texception
private byte i32out = new byte[4];
public void writei32(int i32) throws texception
public void writestring(string str) throws texception catch (unsupportedencodingexception uex)
}public void writebinary(bytebuffer bin) throws texception
public tmessage readmessagebegin() throws texception
return new tmessage(readstring(), (byte)(size & 0x000000ff), readi32());
} else
return new tmessage(readstringbody(size), readbyte(), readi32());
}}public tfield readfieldbegin() throws texception
public string readstring() throws texception catch (unsupportedencodingexception e)
}return readstringbody(size);
}
tprotocol定義了基本的協議資訊,包括傳輸什麼資料,如何解析傳輸的資料的基本方法。
還存在乙個問題,就是伺服器端如何知道客戶端傳送過來的資料是怎麼組合的,比如第乙個欄位是字串型別,第二個欄位是int。這個資訊是在idl生成客戶端時生成的**時提供了。thrift生成的客戶端**提供了讀寫引數的方法,這兩個方式是一一對應的,包括欄位的序號,型別等等。客戶端使用寫引數的方法,伺服器端使用讀引數的方法。
關於idl生成的客戶端**會在後面的文章具體描述。下面簡單看一下自動生成的**
1. 方法的呼叫從writemessagebegin開始,傳送了訊息頭資訊
2. 寫方法的引數,也就是寫訊息體。方法引數由乙個統一的介面tbase描述,提供了read和write的統一介面。自動生成的**提供了read, write方法引數的具體實現
3. 寫完結束
public void write_args(org.apache.thrift.protocol.tprotocol prot) throws org.apache.thrift.texception
public inte***ce tbase, f extends tfieldidenum> extends comparable, serializable
public string identity; // required
public long uid; // required
public string sid; // required
public int type; // required
public string message; // required
public mapparams; // required
/** the set of fields this struct contains, along with convenience methods for finding and manipulating them. */
public enum _fields implements org.apache.thrift.tfieldidenum
oprot.writefieldbegin(uid_field_desc);
oprot.writei64(struct.uid);
oprot.writefieldend();
if (struct.sid != null)
oprot.writefieldbegin(type_field_desc);
oprot.writei32(struct.type);
oprot.writefieldend();
if (struct.message != null)
}// 自動生成的讀方法引數的方法,按照字段順序讀,給伺服器端**使用
public void read(org.apache.thrift.protocol.tprotocol iprot, handle_args struct) throws org.apache.thrift.texception
switch (schemefield.id) else
break;
case 2: // uid
if (schemefield.type == org.apache.thrift.protocol.ttype.i64) else
break;
case 3: // sid
if (schemefield.type == org.apache.thrift.protocol.ttype.string) else
break;
case 4: // type
if (schemefield.type == org.apache.thrift.protocol.ttype.i32) else
break;
}
Thrift學習(二)協議架構
黃色部分是使用者實現的業務邏輯 褐色部分是根據 thrift 定義的服務介面描述檔案生成的客戶端和伺服器端 框架 紅色部分是根據 thrift 檔案生成 實現資料的讀寫操作 紅色部分以下是 thrift 的傳輸體系 協議以及底層 i o 通訊,使用 thrift 可以很方便的自定義乙個服務 傳輸協議...
二 LinkedList原始碼分析
二 linkedlist原始碼分析 上篇看了下arraylist原始碼,這篇記錄下linkedlist原始碼分析 linkedlist 繼承 abstractsequentiallist 提供了對元素順序訪問的抽象 linkedlist 實現 deque介面,底層構成雙向鍊錶結構 linkedlis...
Spring原始碼分析(二)
針對spring中bean初始化時擴充套件類執行順序進行分析 通過getbean逐層最終到bean例項化前後呼叫的方法,主要是aware介面 beanpostprocessor initializingbean init method的呼叫順序 abstractbeanfactory dogetbe...