最近開始正式接觸Thrift架構,很牛B的技術,它被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無論在性能、傳輸大小上有明顯的優勢。
下面看一下windows下的安裝與使用。
Thrift目前最高0.9.1,地址:http://archive.apache.org/dist/thrift/
注意,我們要把exe和tar文件都下載下來,exe用來編譯你的thrift中間語言,而tar解壓后,我們可以看到csharp,php,java,js等多種開發語言的實例代碼,對我們很有幫助的,下載最新版
下載之后,我們把exe文件可以放在C盤,建個Thrift目錄,把它放入,然后可以配置一下環境變量,如圖:
然后,我們就可以進行thrift中間語言的開發了,之所以說它是中間語言,是因為它不是最終我們要使用的,而需要將它進行編譯之后,才生成我們的目標語言,就像C語言,它在編譯時也是生成obj目標語言,然后再二次編譯最終生成exe文件,它們的道理是一樣的,
我們的thrift語言,通過thrift程序可以生成多種編程語言的源代碼。
編碼問題
使用VS建立一個thrift文件后,在進行編譯時出現了問題,最后找到答案,原來是編碼問題,最后使用記事本把編碼被為ANSI就可以正常編譯了。
Hello world程序代碼:
namespace csharp HelloThriftspace exception Xception { 1: i32 errorCode, 2: string message } service HelloThrift{ void HelloWorld() throws (1:Xception ex) }
編譯代碼:
thrift --gen csharp hellothrift.thrift
結果:namespace表示文件夾的所在地,方法,結構,枚舉都是以文件形式存在的
生成的C#代碼:
Xception.cs

namespace HelloThriftspace { #if !SILVERLIGHT [Serializable] #endif public partial class Xception : TException, TBase { private int _errorCode; private string _message; public int ErrorCode { get { return _errorCode; } set { __isset.errorCode = true; this._errorCode = value; } } public string Message { get { return _message; } set { __isset.message = true; this._message = value; } } public Isset __isset; #if !SILVERLIGHT [Serializable] #endif public struct Isset { public bool errorCode; public bool message; } public Xception() { } public void Read (TProtocol iprot) { TField field; iprot.ReadStructBegin(); while (true) { field = iprot.ReadFieldBegin(); if (field.Type == TType.Stop) { break; } switch (field.ID) { case 1: if (field.Type == TType.I32) { ErrorCode = iprot.ReadI32(); } else { TProtocolUtil.Skip(iprot, field.Type); } break; case 2: if (field.Type == TType.String) { Message = iprot.ReadString(); } else { TProtocolUtil.Skip(iprot, field.Type); } break; default: TProtocolUtil.Skip(iprot, field.Type); break; } iprot.ReadFieldEnd(); } iprot.ReadStructEnd(); } public void Write(TProtocol oprot) { TStruct struc = new TStruct("Xception"); oprot.WriteStructBegin(struc); TField field = new TField(); if (__isset.errorCode) { field.Name = "errorCode"; field.Type = TType.I32; field.ID = 1; oprot.WriteFieldBegin(field); oprot.WriteI32(ErrorCode); oprot.WriteFieldEnd(); } if (Message != null && __isset.message) { field.Name = "message"; field.Type = TType.String; field.ID = 2; oprot.WriteFieldBegin(field); oprot.WriteString(Message); oprot.WriteFieldEnd(); } oprot.WriteFieldStop(); oprot.WriteStructEnd(); } public override string ToString() { StringBuilder sb = new StringBuilder("Xception("); sb.Append("ErrorCode: "); sb.Append(ErrorCode); sb.Append(",Message: "); sb.Append(Message); sb.Append(")"); return sb.ToString(); } } }
HelloThrift.cs

namespace HelloThriftspace { public partial class HelloThrift { public interface Iface { void HelloWorld(); #if SILVERLIGHT IAsyncResult Begin_HelloWorld(AsyncCallback callback, object state); void End_HelloWorld(IAsyncResult asyncResult); #endif } public class Client : IDisposable, Iface { public Client(TProtocol prot) : this(prot, prot) { } public Client(TProtocol iprot, TProtocol oprot) { iprot_ = iprot; oprot_ = oprot; } protected TProtocol iprot_; protected TProtocol oprot_; protected int seqid_; public TProtocol InputProtocol { get { return iprot_; } } public TProtocol OutputProtocol { get { return oprot_; } } #region " IDisposable Support " private bool _IsDisposed; // IDisposable public void Dispose() { Dispose(true); } protected virtual void Dispose(bool disposing) { if (!_IsDisposed) { if (disposing) { if (iprot_ != null) { ((IDisposable)iprot_).Dispose(); } if (oprot_ != null) { ((IDisposable)oprot_).Dispose(); } } } _IsDisposed = true; } #endregion #if SILVERLIGHT public IAsyncResult Begin_HelloWorld(AsyncCallback callback, object state) { return send_HelloWorld(callback, state); } public void End_HelloWorld(IAsyncResult asyncResult) { oprot_.Transport.EndFlush(asyncResult); recv_HelloWorld(); } #endif public void HelloWorld() { #if !SILVERLIGHT send_HelloWorld(); recv_HelloWorld(); #else var asyncResult = Begin_HelloWorld(null, null); End_HelloWorld(asyncResult); #endif } #if SILVERLIGHT public IAsyncResult send_HelloWorld(AsyncCallback callback, object state) #else public void send_HelloWorld() #endif { oprot_.WriteMessageBegin(new TMessage("HelloWorld", TMessageType.Call, seqid_)); HelloWorld_args args = new HelloWorld_args(); args.Write(oprot_); oprot_.WriteMessageEnd(); #if SILVERLIGHT return oprot_.Transport.BeginFlush(callback, state); #else oprot_.Transport.Flush(); #endif } public void recv_HelloWorld() { TMessage msg = iprot_.ReadMessageBegin(); if (msg.Type == TMessageType.Exception) { TApplicationException x = TApplicationException.Read(iprot_); iprot_.ReadMessageEnd(); throw x; } HelloWorld_result result = new HelloWorld_result(); result.Read(iprot_); iprot_.ReadMessageEnd(); if (result.__isset.ex) { throw result.Ex; } return; } } public class Processor : TProcessor { public Processor(Iface iface) { iface_ = iface; processMap_["HelloWorld"] = HelloWorld_Process; } protected delegate void ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot); private Iface iface_; protected Dictionary<string, ProcessFunction> processMap_ = new Dictionary<string, ProcessFunction>(); public bool Process(TProtocol iprot, TProtocol oprot) { try { TMessage msg = iprot.ReadMessageBegin(); ProcessFunction fn; processMap_.TryGetValue(msg.Name, out fn); if (fn == null) { TProtocolUtil.Skip(iprot, TType.Struct); iprot.ReadMessageEnd(); TApplicationException x = new TApplicationException (TApplicationException.ExceptionType.UnknownMethod, "Invalid method name: '" + msg.Name + "'"); oprot.WriteMessageBegin(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID)); x.Write(oprot); oprot.WriteMessageEnd(); oprot.Transport.Flush(); return true; } fn(msg.SeqID, iprot, oprot); } catch (IOException) { return false; } return true; } public void HelloWorld_Process(int seqid, TProtocol iprot, TProtocol oprot) { HelloWorld_args args = new HelloWorld_args(); args.Read(iprot); iprot.ReadMessageEnd(); HelloWorld_result result = new HelloWorld_result(); try { iface_.HelloWorld(); } catch (Xception ex) { result.Ex = ex; } oprot.WriteMessageBegin(new TMessage("HelloWorld", TMessageType.Reply, seqid)); result.Write(oprot); oprot.WriteMessageEnd(); oprot.Transport.Flush(); } } #if !SILVERLIGHT [Serializable] #endif public partial class HelloWorld_args : TBase { public HelloWorld_args() { } public void Read (TProtocol iprot) { TField field; iprot.ReadStructBegin(); while (true) { field = iprot.ReadFieldBegin(); if (field.Type == TType.Stop) { break; } switch (field.ID) { default: TProtocolUtil.Skip(iprot, field.Type); break; } iprot.ReadFieldEnd(); } iprot.ReadStructEnd(); } public void Write(TProtocol oprot) { TStruct struc = new TStruct("HelloWorld_args"); oprot.WriteStructBegin(struc); oprot.WriteFieldStop(); oprot.WriteStructEnd(); } public override string ToString() { StringBuilder sb = new StringBuilder("HelloWorld_args("); sb.Append(")"); return sb.ToString(); } } #if !SILVERLIGHT [Serializable] #endif public partial class HelloWorld_result : TBase { private Xception _ex; public Xception Ex { get { return _ex; } set { __isset.ex = true; this._ex = value; } } public Isset __isset; #if !SILVERLIGHT [Serializable] #endif public struct Isset { public bool ex; } public HelloWorld_result() { } public void Read (TProtocol iprot) { TField field; iprot.ReadStructBegin(); while (true) { field = iprot.ReadFieldBegin(); if (field.Type == TType.Stop) { break; } switch (field.ID) { case 1: if (field.Type == TType.Struct) { Ex = new Xception(); Ex.Read(iprot); } else { TProtocolUtil.Skip(iprot, field.Type); } break; default: TProtocolUtil.Skip(iprot, field.Type); break; } iprot.ReadFieldEnd(); } iprot.ReadStructEnd(); } public void Write(TProtocol oprot) { TStruct struc = new TStruct("HelloWorld_result"); oprot.WriteStructBegin(struc); TField field = new TField(); if (this.__isset.ex) { if (Ex != null) { field.Name = "Ex"; field.Type = TType.Struct; field.ID = 1; oprot.WriteFieldBegin(field); Ex.Write(oprot); oprot.WriteFieldEnd(); } } oprot.WriteFieldStop(); oprot.WriteStructEnd(); } public override string ToString() { StringBuilder sb = new StringBuilder("HelloWorld_result("); sb.Append("Ex: "); sb.Append(Ex== null ? "<null>" : Ex.ToString()); sb.Append(")"); return sb.ToString(); } } } }
感覺生成的代碼還是比較麻煩的,希望thrift在以后的產品中,對這塊解決的好一點,呵呵。
下一講我們將進行客戶端與服務器環境的搭建。