C# 高性能RPC,TouchRpc,支持ref和out关键字、流数据、大数据传输


一、序言


二、程序集源码、Demo下载

三、安装

Nuget安装RRQMSocket.RPC即可,具体步骤详看链接博客。

VS、Unity安装和使用Nuget包

四、创建RPC

在之前【RRQMSocket.RPC】C# 创建多协议、多方式、多语言、多平台RPC框架中,已经提到创建服务方法,但是由于没有解析器,所以无法对服务进行下一步设置,那么这节就让我们来详细创建服务吧。

4.1 创建服务

服务器项目中新建一个类,继承于ServerProvider类(或实现IServerProvider),然后在该类中写公共方法,并用RRQMRPC属性标签标记,如果方法有重载,需要重新指定函数键,方法可定义同步执行,也可以定义异步执行

public class MyRpcServer : ServerProvider
{
    [RRQMRPC]
    public string TestOne(int id)//同步服务
    {
        return $"若汝棋茗,id={id}";
    }

    [RRQMRPC("TestOne_Name")]//在重载服务时需要重新设定服务唯一键
    public string TestOne(int id, string name)
    {
        return $"若汝棋茗,Name={name},id={id}";
    }

    [RRQMRPC]
    public void TestOut(out int id)
    {
        id = 10;
    }

    [RRQMRPC]
    public void Testref(ref int id)
    {
        id +=1;
    }

    [RRQMRPC(Async = true)]
    public Task<string> AsyncTestOne(int id)//异步服务,尽量不要用Async结尾,不然生成的异步代码方法将出现两个Async
    {
        return Task.Run(() =>
        {
            return $"若汝棋茗,id={id}";
        });
    }
}

然后,创建TcpRpcParser解析器。在解析器中,设置类似TcpService

private static IRPCParser CreateRRQMTcpParser(int port)
{
    TcpRpcParser tcpRPCParser = new TcpRpcParser();

    //声明配置
    var config = new TcpRpcParserConfig();

    //继承TcpService配置
    config.ListenIPHosts = new IPHost[] {new IPHost(port) };//同时监听两个地址

    //继承TokenService配置
    config.VerifyToken = "123RPC";//连接验证令箭,可实现多租户模式
    config.VerifyTimeout = 3 * 1000;//验证3秒超时

    //继承TcpRpcParser配置,以实现RPC交互
    config.ProxyToken = "RPC";//代理令箭,当客户端获取代理文件,或服务时需验证令箭

    //载入配置
    tcpRPCParser.Setup(config);

    //启动服务
    tcpRPCParser.Start();

    Console.WriteLine($"TCP解析器添加完成,端口号:{port},VerifyToken={tcpRPCParser.VerifyToken},ProxyToken={tcpRPCParser.ProxyToken}");
    return tcpRPCParser;
}

最后添加解析器(添加时需要以键、值方式添加,方便后续查找),然后注册服务即可。

服务器创建完成。

static void Main(string[] args)
{
    //实例化RPCService
    RPCService rpcService = new RPCService();

    //添加解析器,解析器根据传输协议,序列化方式的不同,调用RPC服务
    rpcService.AddRPCParser("tcpRpcParser", CreateRRQMTcpParser(7794));
    
    //注册服务
    rpcService.RegisterServer<MyRpcServer>();

    //注册当前程序集的所有服务
    //rpcService.RegisterAllServer();
    
    //分享代理,代理文件可通过RRQMTool获取。
    rpcService.ShareProxy(new IPHost(8848));
    Console.WriteLine("RPC服务已启动");
}

五、发现、调用RPC服务

实例化TcpRpcClient,然后依托于内部方法,完成服务的发现与调用。

  1. 调用Connect,连接到服务器
  2. 调用DiscoveryService,发现服务
  3. 调用Invoke,传入服务名称、参数,完成调用
static void Main(string[] args)
{
    TcpRpcClient client = new TcpRpcClient();

    var config = new TcpRpcClientConfig();
    config.RemoteIPHost = new IPHost("127.0.0.1:7794");
    client.Setup(config);

    try
    {
        //1.先连接
        client.Connect("123RPC");
        Console.WriteLine("连接成功");

        //2.然后发现服务
        MethodItem[] methodItems = client.DiscoveryService("RPC");
        Console.WriteLine("服务发现成功");

        foreach (var item in methodItems)
        {
            Console.WriteLine($"服务{item.ServerName}中的‘{item.Method}’可以调用");
        }

        Console.WriteLine("按任意键调用TestOne");
        Console.ReadKey();

        //3.调用
        string returnString = client.Invoke<string>("TestOne", InvokeOption.WaitInvoke, 10);

        Console.WriteLine($"调用成功,结果={returnString}");
        Console.ReadKey();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

六、调用痛点

RPC的创建与调用其实是一个比较简单的过程,但是要想更加智能化便捷化的使用,还有很长的一段路要走。

在上述示例中不难发现,RPC的调用实际上是一个非常麻烦难以维护的过程。麻烦的是调用者必须准确的知晓服务方法名称,且要传入类型结构相同的数据类型,尤其是后者,麻烦点甚多。而维护,也是疲不胜烦,每当服务端增加、修改、删除某个服务时,客户端也必须同步修改,这给产品更新,增加了不小的难度。

所以,我们想要的RPC绝不能仅仅是这样的…破玩意。

七 、获取代理文件

获取代理文件详情

八、使用

在引入代理代码(dll或者.cs源码)后,即可以使用代理的类(MyRpcServer)。

使用代理的优点如下:

  • 维护简单,客户端只需要重新运行工具即可获得新代理。
  • 数据结构生成,假如RPC方法的参数是复杂类型,则会直接生成相同结构的数据。
  • 方法说明,客户独很好的得知该方法的注释。
8.1 基础操作
  1. 调用Connect,连接到服务器
  2. 调用DiscoveryService,发现服务
  3. 实例化服务代理,传入IRpcClient实例
  4. 调用代理实例对应方法
static void Main(string[] args)
{
    TcpRpcClient client = new TcpRpcClient();

    var config = new TcpRpcClientConfig();
    config.RemoteIPHost = new IPHost("127.0.0.1:7794");
    client.Setup(config);
    try
    {
        //1.先连接
        client.Connect("123RPC");
        Console.WriteLine("连接成功");

        //2.然后发现服务
        MethodItem[] methodItems = client.DiscoveryService("RPC");
        Console.WriteLine("服务发现成功");

        foreach (var item in methodItems)
        {
            Console.WriteLine($"服务{item.ServerName}中的‘{item.Method}’可以调用");
        }

        Console.WriteLine("按任意键调用TestOne");
        Console.ReadKey();

        //3.实例化服务代理,传入IRpcClient

        MyRpcServer myRpcServer = new MyRpcServer(client);

        //4.通过MyRpcServer代理类直接调用
        string returnString = myRpcServer.TestOne(10);

        Console.WriteLine($"调用成功,结果={returnString}");
        Console.ReadKey();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

8.2 常规用法

实际上,我们在使用RPC时,会再封装一下Client的连接动作,而且还会拦截异常,然后记录日志。

  1. 实例化RpcHandler(也能设置为静态方法)
  2. 调用代理实例对应方法

所以,建议使用示例代码如下:

public class RpcHandler
{
    private TcpRpcClient client;

    private IMyRpcServer myRpcServer;

    public TcpRpcClient Client => client;

    public string IPHost { get => "127.0.0.1:7794"; }


    /// <summary>
    /// 检验client是否在线
    /// 不在线,则重新初始化。
    /// </summary>
    /// <returns></returns>
    public bool CheckOnline()
    {
        if (string.IsNullOrEmpty(IPHost))
        {
            return false;
        }
        try
        {
            if (client == null)
            {
                client = new TcpRpcClient();
                myRpcServer = new MyRpcServer(client);

                TcpRpcClientConfig config = new TcpRpcClientConfig();
                config.RemoteIPHost = new IPHost(IPHost);
                config.VerifyToken = "FileServer";
                client.Setup(config);

                try
                {
                    client.Connect();
                    client.DiscoveryService("FileServerRPC");
                }
                catch
                {
                    return false;
                }
            }
            if (!client.Online)
            {
                client.Dispose();
                client = null;
                myRpcServer = null;
                return CheckOnline();
            }
            return true;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// 此处是示例调用
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public string TestOne(int id)
    {
        try
        {
            if (CheckOnline())
            {
                return myRpcServer.TestOne(id);
            }
            else
            {
                return null;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);//模拟日志记录
            return null;
        }

    }
}

九、高级调用配置

简单的调用,上面已经演示完成,但是,还不足以应对在实际使用中的所有情况,所以可通过高级配置,进行个性化设置。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

若汝棋茗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值