远程对象调用_RPC框架:Thrift的用法解析——附C#源码示例

github源码下载地址:https://github.com/yangwohenmai/OpenSource_Learn/tree/master/%E8%BF%9C%E7%A8%8B%E5%AF%B9%E8%B1%A1%E8%B0%83%E7%94%A8Thrift%E6%A1%86%E6%9E%B6%E5%AD%A6%E4%B9%A0

一、 什么是 RPC

RPC(Remote Procedure Call)远程过程调用,说白了就是客户段远程调用服务端的功能。可以用在微服务架构中。

.Net Core 下的 RPC(远程方法调用)框架有 gRPC、Thrift 等,都支持主流的编程语言。

RPC 虽然效率略高,但是耦合性强,如果兼容性处理不好的话,一旦服务器端接口升级,客户端就要更新,即使是增加一个参数,而 rest 则比较灵活。

最佳实践:对内一些性能要求高的场合用 RPC,对内其他场合以及对外用 Rest。比如 web 服务器和视频转码服务器之间通讯可以用 restful 就够了,转账接口用 RPC 性能会更高一些。 

但这个框架也有缺陷,就是一旦其调用的远程服务运行负荷较重,数据返回的速度就会很慢。

二、 Thrift 使用方法

1.下载thrift http://thrift.apache.org/

把thrift-***.exe解压到磁盘,改名为thrift.exe(用起来方便一些)

2.新建一个XXX.thrift文本文件

首先新建一个txt文本文件,改后缀为thrift。这这时候就得到一个名字为XXX.thrift的文本文件,这个文件中相当于定义了一个客户端和服务端通信的中间件的信息,或者说定义了一个接口的结构。

在这个文件里定义了客户端要调用服务端的所有方法,以及所有通信中要传递的对象。thrift.exe会根据这个文件生成一个RPC项目。

3.thrift编写规则

定义单个变量可以用required optional 两种类型,required关键字定义的参数是对象中必须定义的参数,optional关键字是对象中可选的参数。

struct 关键字可以定义通讯中需要用的对象,struct User { }就是定义一个User对象的结构,里面写的是对象内部的成员变量。

service 关键字定义的是服务端中可供调用的方法,定义的方法可以有返回值回传给客户端。这里定义成service UserService{ },后面thrift就会生成一个叫UserService的接口类,让你去实现接口中定义的方法。

enum 关键字则是定义枚举类

还有一些细节的定义int, bool, string之类的参数,可以参考文档:https://blog.csdn.net/u011642663/article/details/56015576

以下是我定义的程序的thrift接口文件示例,我的文件名字叫UserService.thrift

namespace csharp ThriftTest1.Contract

service UserService{
   SaveResult Save(1:User user)     //定义了一个返回值为SaveResult的方法函数
   User Get(1:i32 id)               //定义了一个返回值为User类型的方法函数
   list GetAll()              //定义了一个返回值为list类型的方法函数
} 

//定义了一个SaveResult 枚举类
enum SaveResult {     
  SUCCESS = 0,  
  FAILED = 1,  
}  

//定义了一个User对象
struct User {
    1: required i64 Id;//对象中的成员:Id,longint类型
    2: required string Name;//对象中的成员:Name,string 类型
    3: required i32 Age;//对象中的成员:Age,int类型
    4: optional bool IsVIP;//对象中的成员:Age,bool 类型
    5: optional string Remark;
}

4.开始生成RPC项目

解压之前下载thrift文件,加压后有一个thrift.exe文件,把thrift.exe文件和刚定义的接口文件XXX.thrift放在同一个文件夹下,启动cmd,在thrift.exe所在文件夹下执行命令

cmd -> thrift.exe -gen csharp UserService.thrift

thrift.exe会根据thrift语法生成相应的C#代码,创建一个类库项目 ThriftTest1.Contract,作为客户端和服务器之间的共用协议,把上一步生成的代码cs文件拷贝到你创建的项目。

在项目中用nuget安装apache-thrift-netcore插件,nuget指令如下:

Install-Package apache-thrift-netcore

此时中间通信层就完成了

三、 创建服务端项目 ThriftTest1.Server,和客户端项目ThriftTest1.Client。

1.

在项目中创建一个服务端server项目和一个客户端client项目。两个项目都要引用ThriftTest1.Contract这个项目。

2.

在server项目中创建一个类,这个类继承UserService.Iface这个接口文件,对接口中的方法进行实现。

3.

client项目可以直接在main方法中调用ThriftTest1.Contract的方法。调用之前要定义好发送请求的ip和端口。

4.

server项目中定义好监听的接口即可。

server端方法如下,创建一个Server类,这个类要实现UserService.Iface接口

using RuPeng.ThriftTest1.Contract;
using System;
using System.Collections.Generic;
using System.Text;

namespace ThriftTest1.Server
{
    public class UserServiceImpl : UserService.Iface//继承UserService.Iface
    {
        public User Get(int id)
        {
            User u = new User();
            u.Id = id;
            u.Name = "用户" + id;
            u.Age = 6;
            return u;
        }

        /// 
        /// 客户端获取数据回传,实现接口方法
        /// 
        /// 
        public List GetAll()
        {
            List list = new List();
            list.Add(new User { Id = 1, Name = "yzk", Age = 18, Remark = "hello" });
            list.Add(new User { Id = 2, Name = "rupeng", Age = 6 });
            return list;
        }

        /// 
        /// 客户端执行一个操作,返回一个值,看是否成功,实现接口方法
        /// 
        /// 
        /// 
        public SaveResult Save(User user)
        {
            if (user.Name == "ERROR")
                return SaveResult.FAILED;
            Console.WriteLine($"保存用户,{user.Id},用户名,{user.Name},用户年龄,{user.Age}");
            return SaveResult.SUCCESS;
        }
    }
}

在server端的main函数中定义好要监听的端口8801

using System;
using Thrift.Server;
using Thrift.Transport;

namespace ThriftTest1.Server
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            TServerTransport transport = new TServerSocket(8801);//监听8801端口
            var processor = new RuPeng.ThriftTest1.Contract.UserService.Processor(new UserServiceImpl());//设置实现类
            TServer server = new TThreadPoolServer(processor, transport);
            server.Serve();
        }
    }
}

在client项目中,定义要发送的IP地址和对应接口8801,调用方法如下

using RuPeng.ThriftTest1.Contract;
using System;
using System.Collections.Generic;
using Thrift.Protocol;
using Thrift.Transport;

namespace ThriftTest1.Client
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            using (TTransport transport = new TSocket("localhost", 8801))
            using (TProtocol protocol = new TBinaryProtocol(transport))
            using (var clientUser = new UserService.Client(protocol))
            {
                transport.Open();
                User u = clientUser.Get(1);
                Console.WriteLine($"{u.Id},{u.Name},{u.Age}");
                List list = clientUser.GetAll();
                Console.WriteLine($"{list[0].Id},{list[0].Name},{list[0].Age},{list[0].Remark}");
                Console.WriteLine($"{list[1].Id},{list[1].Name},{list[1].Age},{list[1].Remark}");
                Console.WriteLine("Finish");
                
                SaveResult rs1 = clientUser.Save(new User(112233, "name11try", 112233));
                Console.WriteLine("执行结果" + rs1);
                SaveResult rs2 = clientUser.Save(new User(332211, "name11tryagain", 332211));
                Console.WriteLine("执行结果" + rs2);
                SaveResult r3 = clientUser.Save(new User(332211, "ERROR", 332211));
                Console.WriteLine("执行结果" + r3);

                Console.ReadLine();
            }
        }
    }
}

完成上述部分,客户端就可以和server端通过8801端口实现远程通信了。

源码在文章开端的github地址下载。

你可能感兴趣的:(小技术_C#)