关于Thrift
下面是来自百度百科关于Thrift的介绍:
thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和引擎,以构建在 C++, Java, Go,Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。
Apache开源地址:http://thrift.apache.org/
Thrift也是.Net平台上一款不错的RPC框架,更何况可以实现与众多编程语言之间的远程调用。下面具体介绍下Thrift在.Net上的用法。
首先,下载Thrift工具,这里选择windows平台的,下载地址:http://www.apache.org/dyn/closer.cgi?path=/thrift/0.11.0/thrift-0.11.0.exe
其次,下载具体的Thrift Sdk包,http://www.apache.org/dyn/closer.cgi?path=/thrift/0.11.0/thrift-0.11.0.tar.gz
内部包含了所支持的语言源码,这里,我们选择csharp目录里的内容,用VS打开,编译生成DLL文件,可供后续使用。
其次,编写Thrift文件,内容如下,这里定义了一个User类,包含一个Int32类型的ID和一个string类型的Name属性,同时,在定义了一个服务,UserService,其中包含GetUserByID和GetAllUser两个方法。 、
struct User { 1: i32 ID 2: string Name } service UserService { User GetUserByID(1:i32 userID) list<User> GetAllUser() }
然后,通过上面下载的Thrif.exe命令行工具,进行代码的生成,windows平台,cmd进入thrift.exe所在目录,执行如下命令:
thrift --gen csharp user.thrift
命令格式如:
thrift --gen <language> <Thrift filename>
也可以把thrift.exe放到指定目录或C盘位置,配置环境变量Path,然后可以直接执行以上命令。
执行完以上命令后,会在当前目录下,生成一个名为gen-csharp的文件夹,里面包含了2个类(User.cs和UserService.cs)。
User.cs代码如下:
/** * Autogenerated by Thrift Compiler (0.11.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated */ using System; using System.Collections; using System.Collections.Generic; using System.Text; using System.IO; using Thrift; using Thrift.Collections; using System.Runtime.Serialization; using Thrift.Protocol; using Thrift.Transport; #if !SILVERLIGHT [Serializable] #endif public partial class User : TBase { private int _ID; private string _Name; public int ID { get { return _ID; } set { __isset.ID = true; this._ID = value; } } public string Name { get { return _Name; } set { __isset.Name = true; this._Name = value; } } public Isset __isset; #if !SILVERLIGHT [Serializable] #endif public struct Isset { public bool ID; public bool Name; } public User() { } public void Read (TProtocol iprot) { iprot.IncrementRecursionDepth(); try { 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) { ID = iprot.ReadI32(); } else { TProtocolUtil.Skip(iprot, field.Type); } break; case 2: if (field.Type == TType.String) { Name = iprot.ReadString(); } else { TProtocolUtil.Skip(iprot, field.Type); } break; default: TProtocolUtil.Skip(iprot, field.Type); break; } iprot.ReadFieldEnd(); } iprot.ReadStructEnd(); } finally { iprot.DecrementRecursionDepth(); } } public void Write(TProtocol oprot) { oprot.IncrementRecursionDepth(); try { TStruct struc = new TStruct("User"); oprot.WriteStructBegin(struc); TField field = new TField(); if (__isset.ID) { field.Name = "ID"; field.Type = TType.I32; field.ID = 1; oprot.WriteFieldBegin(field); oprot.WriteI32(ID); oprot.WriteFieldEnd(); } if (Name != null && __isset.Name) { field.Name = "Name"; field.Type = TType.String; field.ID = 2; oprot.WriteFieldBegin(field); oprot.WriteString(Name); oprot.WriteFieldEnd(); } oprot.WriteFieldStop(); oprot.WriteStructEnd(); } finally { oprot.DecrementRecursionDepth(); } } public override string ToString() { StringBuilder __sb = new StringBuilder("User("); bool __first = true; if (__isset.ID) { if(!__first) { __sb.Append(", "); } __first = false; __sb.Append("ID: "); __sb.Append(ID); } if (Name != null && __isset.Name) { if(!__first) { __sb.Append(", "); } __first = false; __sb.Append("Name: "); __sb.Append(Name); } __sb.Append(")"); return __sb.ToString(); } }
UserService.cs代码如下:
/** * Autogenerated by Thrift Compiler (0.11.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated */ using System; using System.Collections; using System.Collections.Generic; using System.Text; using System.IO; using Thrift; using Thrift.Collections; using System.Runtime.Serialization; using Thrift.Protocol; using Thrift.Transport; public partial class UserService { public interface ISync { User GetUserByID(int userID); List<User> GetAllUser(); } public interface Iface : ISync { #if SILVERLIGHT IAsyncResult Begin_GetUserByID(AsyncCallback callback, object state, int userID); User End_GetUserByID(IAsyncResult asyncResult); #endif #if SILVERLIGHT IAsyncResult Begin_GetAllUser(AsyncCallback callback, object state); List<User> End_GetAllUser(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_GetUserByID(AsyncCallback callback, object state, int userID) { return send_GetUserByID(callback, state, userID); } public User End_GetUserByID(IAsyncResult asyncResult) { oprot_.Transport.EndFlush(asyncResult); return recv_GetUserByID(); } #endif public User GetUserByID(int userID) { #if !SILVERLIGHT send_GetUserByID(userID); return recv_GetUserByID(); #else var asyncResult = Begin_GetUserByID(null, null, userID); return End_GetUserByID(asyncResult); #endif } #if SILVERLIGHT public IAsyncResult send_GetUserByID(AsyncCallback callback, object state, int userID) #else public void send_GetUserByID(int userID) #endif { oprot_.WriteMessageBegin(new TMessage("GetUserByID", TMessageType.Call, seqid_)); GetUserByID_args args = new GetUserByID_args(); args.UserID = userID; args.Write(oprot_); oprot_.WriteMessageEnd(); #if SILVERLIGHT return oprot_.Transport.BeginFlush(callback, state); #else oprot_.Transport.Flush(); #endif } public User recv_GetUserByID() { TMessage msg = iprot_.ReadMessageBegin(); if (msg.Type == TMessageType.Exception) { TApplicationException x = TApplicationException.Read(iprot_); iprot_.ReadMessageEnd(); throw x; } GetUserByID_result result = new GetUserByID_result(); result.Read(iprot_); iprot_.ReadMessageEnd(); if (result.__isset.success) { return result.Success; } throw new TApplicationException(TApplicationException.ExceptionType.MissingResult, "GetUserByID failed: unknown result"); } #if SILVERLIGHT public IAsyncResult Begin_GetAllUser(AsyncCallback callback, object state) { return send_GetAllUser(callback, state); } public List<User> End_GetAllUser(IAsyncResult asyncResult) { oprot_.Transport.EndFlush(asyncResult); return recv_GetAllUser(); } #endif public List<User> GetAllUser() { #if !SILVERLIGHT send_GetAllUser(); return recv_GetAllUser(); #else var asyncResult = Begin_GetAllUser(null, null); return End_GetAllUser(asyncResult); #endif } #if SILVERLIGHT public IAsyncResult send_GetAllUser(AsyncCallback callback, object state) #else public void send_GetAllUser() #endif { oprot_.WriteMessageBegin(new TMessage("GetAllUser", TMessageType.Call, seqid_)); GetAllUser_args args = new GetAllUser_args(); args.Write(oprot_); oprot_.WriteMessageEnd(); #if SILVERLIGHT return oprot_.Transport.BeginFlush(callback, state); #else oprot_.Transport.Flush(); #endif } public List<User> recv_GetAllUser() { TMessage msg = iprot_.ReadMessageBegin(); if (msg.Type == TMessageType.Exception) { TApplicationException x = TApplicationException.Read(iprot_); iprot_.ReadMessageEnd(); throw x; } GetAllUser_result result = new GetAllUser_result(); result.Read(iprot_); iprot_.ReadMessageEnd(); if (result.__isset.success) { return result.Success; } throw new TApplicationException(TApplicationException.ExceptionType.MissingResult, "GetAllUser failed: unknown result"); } } public class Processor : TProcessor { public Processor(ISync iface) { iface_ = iface; processMap_["GetUserByID"] = GetUserByID_Process; processMap_["GetAllUser"] = GetAllUser_Process; } protected delegate void ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot); private ISync 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 GetUserByID_Process(int seqid, TProtocol iprot, TProtocol oprot) { GetUserByID_args args = new GetUserByID_args(); args.Read(iprot); iprot.ReadMessageEnd(); GetUserByID_result result = new GetUserByID_result(); try { result.Success = iface_.GetUserByID(args.UserID); oprot.WriteMessageBegin(new TMessage("GetUserByID", TMessageType.Reply, seqid)); result.Write(oprot); } catch (TTransportException) { throw; } catch (Exception ex) { Console.Error.WriteLine("Error occurred in processor:"); Console.Error.WriteLine(ex.ToString()); TApplicationException x = new TApplicationException (TApplicationException.ExceptionType.InternalError," Internal error."); oprot.WriteMessageBegin(new TMessage("GetUserByID", TMessageType.Exception, seqid)); x.Write(oprot); } oprot.WriteMessageEnd(); oprot.Transport.Flush(); } public void GetAllUser_Process(int seqid, TProtocol iprot, TProtocol oprot) { GetAllUser_args args = new GetAllUser_args(); args.Read(iprot); iprot.ReadMessageEnd(); GetAllUser_result result = new GetAllUser_result(); try { result.Success = iface_.GetAllUser(); oprot.WriteMessageBegin(new TMessage("GetAllUser", TMessageType.Reply, seqid)); result.Write(oprot); } catch (TTransportException) { throw; } catch (Exception ex) { Console.Error.WriteLine("Error occurred in processor:"); Console.Error.WriteLine(ex.ToString()); TApplicationException x = new TApplicationException (TApplicationException.ExceptionType.InternalError," Internal error."); oprot.WriteMessageBegin(new TMessage("GetAllUser", TMessageType.Exception, seqid)); x.Write(oprot); } oprot.WriteMessageEnd(); oprot.Transport.Flush(); } } #if !SILVERLIGHT [Serializable] #endif public partial class GetUserByID_args : TBase { private int _userID; public int UserID { get { return _userID; } set { __isset.userID = true; this._userID = value; } } public Isset __isset; #if !SILVERLIGHT [Serializable] #endif public struct Isset { public bool userID; } public GetUserByID_args() { } public void Read (TProtocol iprot) { iprot.IncrementRecursionDepth(); try { 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) { UserID = iprot.ReadI32(); } else { TProtocolUtil.Skip(iprot, field.Type); } break; default: TProtocolUtil.Skip(iprot, field.Type); break; } iprot.ReadFieldEnd(); } iprot.ReadStructEnd(); } finally { iprot.DecrementRecursionDepth(); } } public void Write(TProtocol oprot) { oprot.IncrementRecursionDepth(); try { TStruct struc = new TStruct("GetUserByID_args"); oprot.WriteStructBegin(struc); TField field = new TField(); if (__isset.userID) { field.Name = "userID"; field.Type = TType.I32; field.ID = 1; oprot.WriteFieldBegin(field); oprot.WriteI32(UserID); oprot.WriteFieldEnd(); } oprot.WriteFieldStop(); oprot.WriteStructEnd(); } finally { oprot.DecrementRecursionDepth(); } } public override string ToString() { StringBuilder __sb = new StringBuilder("GetUserByID_args("); bool __first = true; if (__isset.userID) { if(!__first) { __sb.Append(", "); } __first = false; __sb.Append("UserID: "); __sb.Append(UserID); } __sb.Append(")"); return __sb.ToString(); } } #if !SILVERLIGHT [Serializable] #endif public partial class GetUserByID_result : TBase { private User _success; public User Success { get { return _success; } set { __isset.success = true; this._success = value; } } public Isset __isset; #if !SILVERLIGHT [Serializable] #endif public struct Isset { public bool success; } public GetUserByID_result() { } public void Read (TProtocol iprot) { iprot.IncrementRecursionDepth(); try { TField field; iprot.ReadStructBegin(); while (true) { field = iprot.ReadFieldBegin(); if (field.Type == TType.Stop) { break; } switch (field.ID) { case 0: if (field.Type == TType.Struct) { Success = new User(); Success.Read(iprot); } else { TProtocolUtil.Skip(iprot, field.Type); } break; default: TProtocolUtil.Skip(iprot, field.Type); break; } iprot.ReadFieldEnd(); } iprot.ReadStructEnd(); } finally { iprot.DecrementRecursionDepth(); } } public void Write(TProtocol oprot) { oprot.IncrementRecursionDepth(); try { TStruct struc = new TStruct("GetUserByID_result"); oprot.WriteStructBegin(struc); TField field = new TField(); if (this.__isset.success) { if (Success != null) { field.Name = "Success"; field.Type = TType.Struct; field.ID = 0; oprot.WriteFieldBegin(field); Success.Write(oprot); oprot.WriteFieldEnd(); } } oprot.WriteFieldStop(); oprot.WriteStructEnd(); } finally { oprot.DecrementRecursionDepth(); } } public override string ToString() { StringBuilder __sb = new StringBuilder("GetUserByID_result("); bool __first = true; if (Success != null && __isset.success) { if(!__first) { __sb.Append(", "); } __first = false; __sb.Append("Success: "); __sb.Append(Success== null ? "<null>" : Success.ToString()); } __sb.Append(")"); return __sb.ToString(); } } #if !SILVERLIGHT [Serializable] #endif public partial class GetAllUser_args : TBase { public GetAllUser_args() { } public void Read (TProtocol iprot) { iprot.IncrementRecursionDepth(); try { 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(); } finally { iprot.DecrementRecursionDepth(); } } public void Write(TProtocol oprot) { oprot.IncrementRecursionDepth(); try { TStruct struc = new TStruct("GetAllUser_args"); oprot.WriteStructBegin(struc); oprot.WriteFieldStop(); oprot.WriteStructEnd(); } finally { oprot.DecrementRecursionDepth(); } } public override string ToString() { StringBuilder __sb = new StringBuilder("GetAllUser_args("); __sb.Append(")"); return __sb.ToString(); } } #if !SILVERLIGHT [Serializable] #endif public partial class GetAllUser_result : TBase { private List<User> _success; public List<User> Success { get { return _success; } set { __isset.success = true; this._success = value; } } public Isset __isset; #if !SILVERLIGHT [Serializable] #endif public struct Isset { public bool success; } public GetAllUser_result() { } public void Read (TProtocol iprot) { iprot.IncrementRecursionDepth(); try { TField field; iprot.ReadStructBegin(); while (true) { field = iprot.ReadFieldBegin(); if (field.Type == TType.Stop) { break; } switch (field.ID) { case 0: if (field.Type == TType.List) { { Success = new List<User>(); TList _list0 = iprot.ReadListBegin(); for( int _i1 = 0; _i1 < _list0.Count; ++_i1) { User _elem2; _elem2 = new User(); _elem2.Read(iprot); Success.Add(_elem2); } iprot.ReadListEnd(); } } else { TProtocolUtil.Skip(iprot, field.Type); } break; default: TProtocolUtil.Skip(iprot, field.Type); break; } iprot.ReadFieldEnd(); } iprot.ReadStructEnd(); } finally { iprot.DecrementRecursionDepth(); } } public void Write(TProtocol oprot) { oprot.IncrementRecursionDepth(); try { TStruct struc = new TStruct("GetAllUser_result"); oprot.WriteStructBegin(struc); TField field = new TField(); if (this.__isset.success) { if (Success != null) { field.Name = "Success"; field.Type = TType.List; field.ID = 0; oprot.WriteFieldBegin(field); { oprot.WriteListBegin(new TList(TType.Struct, Success.Count)); foreach (User _iter3 in Success) { _iter3.Write(oprot); } oprot.WriteListEnd(); } oprot.WriteFieldEnd(); } } oprot.WriteFieldStop(); oprot.WriteStructEnd(); } finally { oprot.DecrementRecursionDepth(); } } public override string ToString() { StringBuilder __sb = new StringBuilder("GetAllUser_result("); bool __first = true; if (Success != null && __isset.success) { if(!__first) { __sb.Append(", "); } __first = false; __sb.Append("Success: "); __sb.Append(Success); } __sb.Append(")"); return __sb.ToString(); } } }
最后,我们新建3个项目,一个Server,一个Client,一个Service(定义的服务),结构如下:
让我们先看看ThrifServer服务端吧。
/// <summary> /// /// </summary> /// <param name="args"></param> static void Main(string[] args) { Console.Title = "Thrift服务端-Server"; TServerSocket serverTransport = new TServerSocket(8080, 0, false); UserService.Processor processor = new UserService.Processor(new Services.TheUserService()); TServer server = new TSimpleServer(processor, serverTransport); Console.WriteLine("启动服务器,监听端口8080 ..."); server.Serve(); }
这里启动服务。在服务端,我们定义了一个TheUserService类,来实现Service中定义的成员。
/// <summary> /// 用户服务 /// </summary> public class TheUserService:Iface { /// <summary> /// /// </summary> /// <param name="userID"></param> /// <returns></returns> public User GetUserByID(int userID) { return new User() { ID = 1, Name = "lichaoqiang" }; } /// <summary> /// /// </summary> /// <returns></returns> public List<User> GetAllUser() { List<User> users = new List<User>(){ new User() { ID = 1, Name = "lichaoqiang" }, new User() { ID = 2, Name = "yuyuangfang" } }; return users; } }
Thrift客户端:
/// <summary> /// /// </summary> /// <param name="args"></param> static void Main(string[] args) { Console.Title = "Thrift客户端-Client"; TTransport transport = new TSocket("10.10.10.12", 8080); TProtocol protocol = new TJSONProtocol(transport); UserService.Client client = new UserService.Client(protocol); transport.Open(); //var users = client.GetAllUser(); //users.ForEach(u => Console.WriteLine(string.Format("User ID : {0}, User Name {1}", u.ID, u.Name))); var user = client.GetUserByID(1); Console.WriteLine("------------------"); Console.WriteLine(string.Format("User ID : {0}, User Name {1}", user.ID, user.Name)); Console.ReadLine(); }
完成以上步骤后,让我们启动服务端和客户端,来看看效果吧!