最近开始正式接触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在以后的产品中,对这块解决的好一点,呵呵。
下一讲我们将进行客户端与服务器环境的搭建。