.Net RPC框架Thrift的用法

时间:2022-12-23 20:59:16

  关于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(定义的服务),结构如下:

.Net RPC框架Thrift的用法

让我们先看看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();
}

  完成以上步骤后,让我们启动服务端和客户端,来看看效果吧!

.Net RPC框架Thrift的用法