Thrift 简单实现C#通讯服务程序 (跨语言 MicroServices)
Thrift是一种可伸缩的跨语言服务框架,它结合了功能强大的软件堆栈的代码生成引擎,以建设服务,工作效率和无缝地与C++,C#,Java,Python和PHP和Ruby结合。thrift允许你定义一个简单的定义文件中的数据类型和服务接口。以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。 它的好处是什么?当然是它支持大多数时下流行的语言。通过Thrift命令自动生成相应的语言脚本。而进行一些性能对比中,它的好处显而易见。
以上是传输相同的内容时内容大小的对比。
以上是运行开销比较结果。
TCompactProtocol和TBinaryProtocol是Thrift支持的两种协议,其中TCompactProtocol使用Variable-Length Quantity (VLQ) 编码对数据进行压缩。
详细可以查看:http://www.javabloger.com/article/apache-thrift-architecture.html
接下来,我想讲述一下如何使用Thrift搭建C#版的客户端以及服务端通讯的程序。
1. 先从官网下载Thrift安装包以及签出SVN源码:
官网下载地址:http://thrift.apache.org/download/
这里我下载了一个Thrift compiler for Windows版本的EXE文件(thrift-0.7.0.exe)
签出SVN源码地址:http://svn.apache.org/repos/asf/thrift/trunk
2. 这里我利用文章(http://www.javabloger.com/article/thrift-java-code-example.html)的例子(该例子生成Java源码的),完成一个C#版本的示例。
3. 首先创建脚本,命名为textCsharp.thrift,脚本内容如下:
namespace java com.javabloger.gen.code # 注释1 struct Blog { # 注释2 1: string topic 2: binary content 3: i64 createdTime 4: string id 5: string ipAddress 6: map<string,string> props } service ThriftCase { # 注释3 i32 testCase1(1:i32 num1, 2:i32 num2, 3:string num3) # 注释4 list<string> testCase2(1:map<string,string> num1) void testCase3() void testCase4(1:list<Blog> blog) }
4. 执行thrift命令:thrift -gen csharp testCsharp.thrift,这里说明一下:参数"csharp”意味着这里将自动生成C#代码,如果这里写java,python等等,可以用"java"或者"py”代替。
于是得到gen-csharp的目录,这个目录里面就包含支持Thrift的Blog以及ThriftCase的源代码,具体里面都生成什么代码,后面会做出介绍。
5. 然后,我现在打开SVN源码中的 trunk\lib\csharp\ 路径,我用项目打开
编译后,得到Thrift.dll文件,为了后面使用Thrift做准备。
6.新建工程,添加Server以及Client项目,把刚才生成的代码文件放入Common项目中。让Client和Server项目引用Thrift.dll类库。
7. 编写服务端程序:
public class Server { public void Start() { TServerSocket serverTransport = new TServerSocket(7911, 0, false); ThriftCase.Processor processor = new ThriftCase.Processor(new BusinessImpl()); TServer server = new TSimpleServer(processor, serverTransport); Console.WriteLine("Starting server on port 7911 ..."); server.Serve(); } }
其中BusinessImpl具体提供业务逻辑的实现:
public class BusinessImpl : ThriftCase.Iface { public int testCase1(int num1, int num2, String num3) { int i = num1 + num2; Console.Write( "testCase1 num1+num2 is :"+ i); Console.WriteLine( " num3 is :"+ num3); return i; } public List<String> testCase2(Dictionary<String, String> num1) { Console.WriteLine("testCase2 num1 :" + num1); List<String> list = new List<String>(); list.Add("num1"); return list; } public void testCase3() { Console.WriteLine("testCase3 ..........." + DateTime.Now); } public void testCase4(List<Blog> blogs) { Console.WriteLine("testCase4 ..........."); for (int i = 0; i < blogs.Count; i++) { Blog blog = blogs[i]; Console.Write("id:" + blog.Id); Console.Write(",IpAddress:" + blog.IpAddress); //Console.Write (",Content:" + new String(blog.Content)); Console.Write(",topic:" + blog.Topic); Console.Write(",time:" + blog.CreatedTime); } Console.WriteLine("\n"); } }
让它继承ThriftCase.Iface接口。
8. 编写客户端程序:
class Client { static Dictionary<String, String> map = new Dictionary<String, String>(); static List<Blog> blogs = new List<Blog>(); static void Main(string[] args) { TTransport transport = new TSocket("localhost", 7911); TProtocol protocol = new TBinaryProtocol(transport); ThriftCase.Client client = new ThriftCase.Client(protocol); transport.Open(); Console.WriteLine("Client calls ....."); map.Add("blog", "http://www.javabloger.com%22);/ client.testCase1(10, 21, "3"); client.testCase2(map); client.testCase3(); Blog blog = new Blog(); //blog.setContent("this is blog content".getBytes()); blog.CreatedTime = DateTime.Now.Ticks; blog.Id = "123456"; blog.IpAddress = "127.0.0.1"; blog.Topic = "this is blog topic"; blogs.Add(blog); client.testCase4(blogs); transport.Close(); Console.ReadKey(); } }
9. 运行Server以及Client:
从客户端调用的方法,服务端已经接收到了数据。
源代码下载:ThriftCSharp.rar