IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 【RRQMSocket.RPC】C# RRQMRPC的高级使用设置 -> 正文阅读

[网络协议]【RRQMSocket.RPC】C# RRQMRPC的高级使用设置


一、序言

本节须知

在学习本节之前,您必须熟悉RRQM中的TcpRpcParser解析器与TcpRpcClient客户端(或其派生类,例如文件传输)的创建,如果您不熟悉,请在下列链接中了解。


二、程序集源码、Demo下载

2.1 源码位置

RRQMSocket

2.2 Demo位置

RRQMBox

三、安装

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

VS、Unity安装和使用Nuget包

四、序列化选择

从下图(图片来源网络)可以看出,序列化是RPC中至关重要的一个环节,可以说,序列化的优劣,会很大程度的影响RPC调用性能。

在这里插入图片描述

4.1 RRQM支持的序列化

在RRQMRPC中,内置了四种序列化方式,分别为RRQMBinarySystemBinaryJsonXml。这四种方式的特点,就是其序列化的特点。

RRQMBinarySystemBinaryJsonXml
特点序列化方式速度快,数据量小,但是兼容的数据格式也比较有限。仅支持基础类型、自定义实体类、数组、List、字典保真度高,支持接口,抽象类,object,泛型等类型的序列化,但是需要Serializable的标签,且必须是同一类型(或重写映射图谱)兼容性好,可读性强,但是受字符串影响,性能不出众,且数据量受限制兼容性一般,可读性强,同样受字符串影响,性能不出众,且数据量受限制

4.2 使用预设序列化

在RRQMRPC中,选择序列化是非常简单的,且序列化方式完全由调用端决定。

在实际的调用中,通过InvokeOption的参数指定。
在这里插入图片描述
实际上,只需要传入相关参数即可。

InvokeOption invokeOption = new InvokeOption();
invokeOption.SerializationType = RRQMCore.Serialization.SerializationType.RRQMBinary;
//invokeOption.SerializationType = RRQMCore.Serialization.SerializationType.Json;
//invokeOption.SerializationType = RRQMCore.Serialization.SerializationType.SystemBinary;
//invokeOption.SerializationType = RRQMCore.Serialization.SerializationType.Xml;

string returnString = client.Invoke<string>("TestOne", invokeOption, "10");

4.3 自定义序列化

a).定义
想要实现自定义序列化,必须通过重写序列化选择器,实现SerializeParameterDeserializeParameter函数。如果还想留用预设序列化,请按下代码示例即可。

public class MySerializationSelector: SerializationSelector
{
    /// <summary>
    /// 反序列化
    /// </summary>
    /// <param name="serializationType"></param>
    /// <param name="parameterBytes"></param>
    /// <param name="parameterType"></param>
    /// <returns></returns>
    public override object DeserializeParameter(SerializationType serializationType, byte[] parameterBytes, Type parameterType)
    {
        if (parameterBytes == null)
        {
            return parameterType.GetDefault();
        }
        switch (serializationType)
        {
            case SerializationType.RRQMBinary:
                {
                    return SerializeConvert.RRQMBinaryDeserialize(parameterBytes, 0, parameterType);
                }
            case SerializationType.SystemBinary:
                {
                    return SerializeConvert.BinaryDeserialize(parameterBytes, 0, parameterBytes.Length);
                }
            case SerializationType.Json:
                {
                    return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(parameterBytes), parameterType);
                }
            case SerializationType.Xml:
                {
                    return SerializeConvert.XmlDeserializeFromBytes(parameterBytes, parameterType);
                }
            case (SerializationType)4:
                {
                    //此处可自行实现
                    return default;
                }
            default:
                throw new RRQMRPCException("未指定的反序列化方式");
        }
    }

    /// <summary>
    /// 序列化参数
    /// </summary>
    /// <param name="serializationType"></param>
    /// <param name="parameter"></param>
    /// <returns></returns>
    public override byte[] SerializeParameter(SerializationType serializationType, object parameter)
    {
        if (parameter == null)
        {
            return null;
        }
        switch (serializationType)
        {
            case SerializationType.RRQMBinary:
                {
                    return SerializeConvert.RRQMBinarySerialize(parameter, true);
                }
            case SerializationType.SystemBinary:
                {
                    return SerializeConvert.BinarySerialize(parameter);
                }
            case SerializationType.Json:
                {
                    return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(parameter));
                }
            case SerializationType.Xml:
                {
                    return SerializeConvert.XmlSerializeToBytes(parameter);
                }
            case (SerializationType)4:
                {
                    //此处可自行实现
                    return default;
                }
            default:
                throw new RRQMRPCException("未指定的序列化方式");
        }
    }
}

b).使用
首先在解析器客户端配置中赋值解析器。
在这里插入图片描述

然后,因为赋值时是SerializationType的枚举类型,所以执行强制类型转换即可。

InvokeOption invokeOption = new InvokeOption();
invokeOption.SerializationType = (RRQMCore.Serialization.SerializationType)4;

五、调用反馈类型

5.1 类型说明

RRQMRPC的调用状态有三种状态可选,分别为:OnlySendWaitSendWaitInvoke。区别是:

OnlySendWaitSendWaitInvoke
仅发送RPC请求,在TCP底层协议下,能保证发送成功,但是不反馈服务器任何状态,也不会取得返回值异常等信息。在UDP底层协议下,不保证发送成功,仅仅是具有请求动作而已。发送RPC请求,并且等待收到状态返回,能保证RPC请求顺利到达服务,但是不能得知RPC服务是否成功执行,也不会取得返回值异常等信息发送RPC请求,且返回所有信息,包括是否成功调用,执行后的返回值异常等信息。

5.2 使用

同样的,在InvokeOption中可以直接赋值使用。

InvokeOption invokeOption = new InvokeOption();

invokeOption.FeedbackType = FeedbackType.WaitInvoke;
//invokeOption.FeedbackType = FeedbackType.OnlySend;
//invokeOption.FeedbackType = FeedbackType.WaitSend;

string returnString = client.Invoke<string>("TestOne", invokeOption, "10");

六、调用超时设置

调用RPC,不能无限制等待,必须要有计时器,或者任务取消的功能。

6.1 计时器设置

直接对InvokeOptionTimeout 属性赋值即可,单位为毫秒

InvokeOption invokeOption = new InvokeOption();

invokeOption.Timeout = 1000 * 10;//10秒后无反应,则抛出RRQMTimeoutException异常

string returnString = client.Invoke<string>("TestOne", invokeOption, "10");

6.2 任务取消

在RPC调用时,计时器是一个好的选择,但是还不够完美,有时候我们希望能手动终结某个调用任务。这时候,计时器就不堪重任,需要能主动取消任务的功能。熟悉.net的小伙伴都知道,CancellationToken是具备这个功能的。同样的,只需要对InvokeOptionCancellationToken 赋值即可。

InvokeOption invokeOption = new InvokeOption();

CancellationTokenSource tokenSource = new CancellationTokenSource();
invokeOption.CancellationToken = tokenSource.Token;

//tokenSource.Cancel();//调用时取消任务

string returnString = client.Invoke<string>("TestOne", invokeOption, "10");

七、调用服务实例

调用的服务,必须由承载服务的实例参与完成,但是,实例的不同,其调用结果大相径庭。

例如:在TestInstanceRpcServer服务中定义了Count属性和Increment函数。每次调用IncrementCount会递增,然后返回Count值。如果某个客户端连续调用两次,会得到什么值呢?亦或者,某两个客户端,各调用一次,会得到什么值呢?

想必你心里已经有了答案,但是,我要告诉你,你都答案是错误的!Error!Error!

因为,答案既是你想的,也不是你想的。

public class TestInstanceRpcServer : ServerProvider
{
    public int Count { get; set; }

    [RRQMRPC]
    public int Increment()//同步服务
    {
        return ++Count;
    }
}

7.1 服务实例类型

实际上,RRQMRPC中,支持三种服务实例类型,分别为GlobalInstanceCustomInstanceNewInstance,三者的区别如下。

GlobalInstanceCustomInstanceNewInstance
全局实例,即所有客户端,调用一个实例,在上述案例中,Count值会一直递增。用户拥有实例,即一个RPC连接调用一个实例,在上述案例中,Count会在同一客户端调用时递增,在不同客户端中重新计数。新实例,即每次调用,都使用新实例,在上述案例中,获得的Count会一直等于1。

7.2 服务实例类型选择

服务类型,实际实际上还是由InvokeOption设置。

InvokeOption invokeOption = new InvokeOption();

invokeOption.InvokeType = RRQMSocket.RPC.InvokeType.CustomInstance;
//invokeOption.InvokeType = RRQMSocket.RPC.InvokeType.GlobalInstance;
//invokeOption.InvokeType = RRQMSocket.RPC.InvokeType.NewInstance;

string returnString = client.Invoke<string>("TestOne", invokeOption, "10");

八、获取调用终端

RPC服务是无状态的,即只知道当前服务被调用,但无法得知是被谁调用,这个问题给日志记录、RPC回调等带来了很多麻烦事。但是,RRQMRPC支持调用终端获取。

步骤:

  1. RRQMRPC标签需要传入IncludeCallContext参数。
  2. 定义的服务的第一个参数必须是IServerCallContext或其派生类。
  3. 最后获得其Caller属性即可得到调用者。
public class GetCallerRpcServer : ServerProvider
{
    [RRQMRPC(MethodFlags.IncludeCallContext)]
    public string GetCallerID(IServerCallContext callContext)
    {
        if (callContext.Caller is RpcSocketClient socketClient)
        {
            return socketClient.ID;
        }
        return null;
    }

    [RRQMRPC(MethodFlags.IncludeCallContext)]
    public string GetCallerID_2(RpcServerCallContext callContext)
    {
        if (callContext.Caller is RpcSocketClient socketClient)
        {
            return socketClient.ID;
        }
        return null;
    }
}

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-11-26 09:12:22  更:2021-11-26 09:13:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 7:17:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码