Remoting中的方法回调

远程回调Remoting 【代码】远程回调Remoting。 阅读详情

Net Remoting(远程方法回调) - Part.4

1. 远程回调方式说明

远程方法回调通常有两种方式:

  • 客户端也存在继承自MarshalByValueObject的类型,并将该类型的实例作为参数传递给了远程对象的方法,然后远程对象在其方法中通过该类型实例的引用对它进行调用(访问其属性或者方法)。记得继承自MarshalByValueObject的类型实例永远不会离开自己的应用程序域,所以相当于服务端对象调用了客户端对象。
  • 客户端对象注册了远程对象发布的事件,远程对象通过委托调用客户端注册了的方法。

当服务端调用客户端的方法时,它们的角色就互换了。此时,需要注意这样几个问题:

  1. 因为不能通过对象引用访问静态方法(属性),所以无法对静态方法(属性)进行回调。
  2. 由于服务端在运行时需要访问客户端对象,此时它们的角色互换,需要在服务端创建对客户端对象的代理,所以服务端也需要客户端对象的类型元数据。因此,最好将客户端需要回调的方法,抽象在一个对象中,服务端只需引用含有这个对象的程序集就可以了。而如果直接写在Program中,服务端还需要引用整个客户端。
  3. 由于将客户端进行回调的逻辑抽象成为了一个独立的对象,此时客户端的构成就类似于前面所讲述的服务端。它包含两部分:(1)客户端对象,用于支持服务端的方法回调,以及其它的业务逻辑;(2)客户端控制台应用程序(也可以是其它类型程序),它仅仅是注册通道、注册端口、注册远程对象,提供一个客户端对象的运行环境。

根据这三点的变化,我们可以看出:客户端含有客户端对象,但它还需要远程服务对象的元数据来构建代理;服务端含有服务对象,但它还需要客户端对象的元数据来构建代理。因此,客户端服务端均需要服务对象、客户对象的类型元数据,简单起见,我们将它们写在同一个程序集中,命名为ShareAssembly,供客户端、服务端引用。此时,运行时的状态图如下所示:

其中ShareAssembly.dll包含服务对象和客户端对象的代码。接下来一节我们来看一下它们的代码。

2.客户端和服务端对象

2.1服务端对象

由于本文讨论的主要是回调,所以我们创建新的服务对象和客户对象来进行演示。下面是ShareAssembly程序集包含的代码,我们先看一下服务端对象和委托的定义:

public delegate void NumberChangedEventHandler(string name, int count);

public class Server :MarshalByRefObject {
    private int count = 0;
    private string serverName = "SimpleServer";

    public event NumberChangedEventHandler NumberChanged;

    // 触发事件,调用客户端方法
    [MethodImpl(MethodImplOptions.Synchronized)]
    public void DoSomething() {
        // 做某些额外方法
        count++;
        if (NumberChanged != null) {
            Delegate[] delArray = NumberChanged.GetInvocationList();
            foreach (Delegate del in delArray) {
                NumberChangedEventHandler method = (NumberChangedEventHandler)del;
                try {
                    method(serverName, count);
                } catch {
                    Delegate.Remove(NumberChanged, del);//取消某一客户端的订阅
                }
            }              
        }
    }

    // 直接调用客户端方法
    public void InvokeClient(Client remoteClient, int x, int y) {
        int total = remoteClient.Add(x, y); //方法回调
        Console.WriteLine(
            "Invoke client method: x={0}, y={1}, total={2}",x, y, total);
    }

    // 调用客户端属性
    public void GetCount(Client remoteClient) {
        Console.WriteLine("Count value from client: {0}", remoteClient.Count);
    }
}

在这段代码中首先定义了一个委托,并在服务对象Server中声明了一个该委托类型的事件,它可以用于客户对象注册。它主要包含三个方法:DoSomething()、InvokeClient()和GetCount()。需要注意的是DoSomething()方法,因为我后面将服务端实现为了Singleton模式,所以需要处理并发访问,我使用了一种简便的方法,向方法添加MethodImp特性,它会自动实施方法的线程安全。其次就是在方法中触发事件时,我采用了遍历委托链表的方式,并放在了try/catch块中,因为触发事件时客户端有可能已经不存在了。另外,如果发生异常,我将它从订阅的委托列表中删除掉,这样下次触发时就不会再次调用它了。这里也可以采用BeginInvoke()进行异步调用,具体可以参见C#中的委托和事件(续)一文。

InvokeClient()方法调用了客户端的Add()方法,并向控制台输出了提示性的说明;GetCount()方法获取了客户端Count的值,并产生了输出。注意这三个方法均由客户端调用,但是方法内部又回调了调用它们的客户对象。

2.2客户端对象

接下来我们看下客户端的代码,它没有什么特别,OnNumberChanged()方法在事件触发时自动调用,而其余两个方法由服务对象进行回调,并在调用它时,在客户端控制台输出相应的提示:

public class Client : MarshalByRefObject {
    private int count = 0;
   
    // 方式1:供远程对象调用
    public int Add(int x, int y) {
        // 当有服务端调用时,打印下面一行
        Console.WriteLine("Add callback: x={0}, y={1}.", x, y);
        return x + y;
    }

    // 方式1:供远程对象调用
    public int Count {
        get {
            count++;
            return count;
        }
    }

    // 方式2:订阅事件,供远程对象调用
    public void OnNumberChanged(string serverName, int count){
        Console.WriteLine("OnNumberChanged callback:");
        Console.WriteLine("ServerName={0}, Server.Count={1}", serverName, count);
    }
}

注意一下Count属性,它在输出前进行了一次自增,等下运行时我们会重新看这里。

3.服务端、客户端会话模型

当客户对象调用服务对象方法时,服务端已经注册了通道、开放了端口,对请求进行监听。同理,当服务端回调客户端对象时,客户端也需要注册通道、打开端口。但现在问题是:服务端如何知道客户端使用了哪个端口?我们在Part.1中提到过,当对象进行传引用封送时,会包含对象的位置,而有了这个位置,再加上类型的元数据便可以创建代理,代理总是知道远程对象的地址,并将请求发送给远程对象。这种会话模型可以用下面的图来表述:

从上面这幅图可以很清楚地看到服务端代理的创建过程:首先在第1阶段,客户端服务端谁也不知道谁在哪儿;因此,在第2阶段,我们首先要为客户端提供服务端对象的地址和类型元数据,有了这两样东西,客户端便可以创建服务端的代理,然后通过代理就访问到服务端对象;第3阶段是最关键的一步,在客户端通过代理调用InvokeClient()时,将client对象以传引用封送的方式传递了过去,我们前面说过,在传引用封送时,它还包括了这个对象的位置,也就是client对象的位置和端口号;第4步时,服务端根据客户端位置和类型元数据创建了客户端对象的代理,并通过代理调用了客户端的Add()方法。

NOTE:图中的代理实际应该分别指向client或者server,由于绘图的空间问题,我就直接指在框框上了。

因此,客户端应用程序与之前相比一个最大的区别就是需要注册通道,除此以外,它并不需要明确地指定一个端口号,可以由.NET自动选择一个端口号,而服务端则会通过客户端代理知道其使用的是哪个端口号。

4.宿主应用程序

4.1服务端宿主应用程序

现在我们来看一下服务端宿主应用程序的实现。简单起见,我们依然创建一个控制台应用程序ServerConsole,然后在解决方案下添加前面创建的ShareAssembly项目,然后在ServerConsole中引用ShareAssembly。

NOTE:在这里我喜欢将解决方案和项目起不同的名称,比如解决方案我起名为ServerSide(服务端),服务端控制台应用程序则叫ServerConsole。这样感觉更清晰一些。

服务端控制台应用程序的代码和前面的类似,还是老一套的注册通道,注册对象,需要注意的是这里采用了自定义formatter的方式,并设置了它的TypeFilterLevel属性为TypeFilterLevel.Full,它默认为Low,但是当设为Low时一些复杂的类型将无法进行Remoting(主要是出于安全性的考虑)。

// using... 略
class Program {
    static void Main(string[] args) {

        // 设置Remoting应用程序名
        RemotingConfiguration.ApplicationName = "CallbackRemoting";

        // 设置formatter
        BinaryServerFormatterSinkProvider formatter;
        formatter = new BinaryServerFormatterSinkProvider();
        formatter.TypeFilterLevel = TypeFilterLevel.Full;

        // 设置通道名称和端口
        IDictionary propertyDic = new Hashtable();
        propertyDic["name"] = "CustomTcpChannel";
        propertyDic["port"] = 8502;

        // 注册通道
        IChannel tcpChnl = new TcpChannel(propertyDic, null, formatter);
        ChannelServices.RegisterChannel(tcpChnl, false);

        // 注册类型
        Type t = typeof(Server);
        RemotingConfiguration.RegisterWellKnownServiceType(
            t, "ServerActivated", WellKnownObjectMode.Singleton);

        Console.WriteLine("Server running, model: Singleton/n");
        Console.ReadKey();
    }
}

4.2客户端宿主应用程序

与服务端类似,我们创建解决方案ClientSide,在其下添加ClientConsole控制台项目,添加现有的ShareAssembly项目,并在ClientConsole项目下添加对ShareAssembly的引用。

//using... 略
class Program {
    static void Main(string[] args) {

        // 注册通道
        IChannel chnl = new TcpChannel(0);
        ChannelServices.RegisterChannel(chnl, false);

        // 注册类型
        Type t = typeof(Server);
        string url = "tcp://127.0.0.1:8502/CallbackRemoting/ServerActivated";
        RemotingConfiguration.RegisterWellKnownClientType(t, url);

        Server remoteServer = new Server(); // 创建远程对象
        Client localClient = new Client();  // 创建本地对象

        // 注册远程对象事件
        remoteServer.NumberChanged +=
            new NumberChangedEventHandler(localClient.OnNumberChanged);

        remoteServer.DoSomething();             // 触发事件
        remoteServer.GetCount(localClient);     // 调用GetCount()
        remoteServer.InvokeClient(localClient, 2, 5);// 调用InvokeClient()

        Console.ReadKey();  // 暂停客户端
    }
}

我们看一下上面的代码,它仅仅是多了一个通道注册,注意我们将端口号设置为0,意思是由.NET选择一个可用端口。由于注册了远程类型,所以我们直接使用new操作创建了一个Server对象。然后,我们创建了一个本地的Client对象,注册了NumberChanged事件、触发事件、调用了GetCount()方法和InvokeClient()方法。最后,我们暂停了客户端,为什么这里暂停,而不是直接结束,我们下面运行时再解释。

5.程序运行测试

5.1运行一个客户端

我们运行先服务端,接着运行一个客户端,此时产生的输出如下:

上面是服务端,下面是客户端。我们在调用server.DoSomething()方法时,触发了事件,所以调用了客户端的OnNumberChanged,产生了客户端的前两行输出;调用GetCount()时,客户端没有产生输出,服务端输出了“Count value from client:1”;调用InvokeClient()时,客户端和服务端分别产生了相应的输出。

5.2运行多个客户端

接下来,我们不要关闭上面的窗口,再次打开一个客户端。此时程序的运行结果如下所示,其中第1幅图是服务端、第2幅图是第一个客户端、第3幅图是新开启的客户端:

这里可以发现两点:由于第二个客户端再次调用了DoSomething()方法,所以它再次触发了事件,因此在第一个客户端再次产生了输出“OnNumberChanged Callback...”;再次调用GetCount()方法时,对于服务端来说,是一个新建的客户端localClient对象,所以count值继续输出为1,也就是说两个客户端对象是独立的,对服务器来说,可以将客户端视为客户激活方式(Client-Actived Model)。

5.3 关闭第一个客户端,再新建一个客户端

这种情况主要用来测试当服务端触发事件时,之前订阅了事件的客户端已经不存在了的情况。由于我们已经在服务端对象中进行了异常处理,可以看到不会出现任何错误,程序会按照预期的执行。

这里还有另外一种方式,就是将客户端的回调方法使用OneWay特性进行标记,然后服务端对象触发事件时直接使用NumberChanged委托变量。当客户端方法用OneWay标记后,.NET会自动实施异步调用,并且在客户端产生异常时也不会影响到服务端的运行。

5.3的例子就不演示了,感兴趣可以自己试一下。

.NET Remoting 技术深度解析:原理、实现与演进 摘要: .NET Remoting 是 .NET 框架中用于跨应用程序域通信的分布式系统技术,支持对象在不同应用程序域、进程或物理机器间交互。其核心概念包括应用程序域、远程对象、代理、通道和格式化器。系统架构通过代理、通道和格式化器实现消息传递,支持多种激活模式和通道类型。代码示例展示了远程对象的定义、服务器端和客户端的实现,以及通过配置文件进行配置的方式。.NET Remoting 为构建分布式应用提供了基础架构,适用于高性能内网通信、跨防火墙互联网通信等场景。 阅读详情

相关推荐

25、.NET Remoting 中的异步调用与回调方法详解

本文详细解析了 .NET Remoting 中的异步调用与回调方法,包括如何获取异步调用的返回值、使用轮询检查完成状态以及通过 AsyncCallback 实现回调通知机制。文章还提供了完整的代码示例,涵盖了 C# 和 VB 两种语言,并通过实验步骤演示了如何创建远程对象并进行异步方法调用。最后,对不同异步处理方式进行了对比,并给出了代码优化建议和常见问题的解决方案,适用于分布式系统、实时数据处理及云计算等场景。

sugar的博客 74

.NET Remoting 一种跨应用程序域或跨网络的通信框架

服务器端接收器又分为服务环境接收器(context sink)和对象环境接收器(object sink),它们分别位于信道和远程对象之间、远程对象和方法调用之间。代理对象:代理对象是指客户端应用程序中代表远程对象的对象,它们负责将客户端对远程对象的方法调用转换为消息,并通过信道发送给服务器端。透明代理是由 CLR 自动生成的,它实现了远程对象所实现的接口,并重写了所有方法,使得客户端可以像调用本地对象一样调用远程对象。远程对象可以是单例的,也可以是每次请求都创建一个新实例的。

polsnet的专栏 1051

CoreRemoting:具有经典.NET Remoting风格的RPC库

核心远程处理 具有经典.NET Remoting风格的RPC库(.NET Standard 2.0) NuGet软件包: : 这是为了什么? 帮助将使用.NET Remoting的应用程序迁移到.NET Core / .NET 5。 提供易于使用的RPC功能 在分布式应用程序中支持事件和委托 在Linux,Windows和Mac上运行 这不是为了什么? 为Javascript客户端创建REST-API 创建SOAP Web服务 与.NET以外的其他平台一起使用 创建需要在多个群集节点上运行的服务器应用程序 事实与特征 在运行时为远程服务创建代理对象(在后台使用Castle.DynamicProxy) 服务可以具有SingleCall或Singeton生命周期 默认情况下使用websocket进行TCP双工网络通信(基于webshocket-sharp) 可以插入自定义传输

.Net Remoting(基本操作) - Part.2

 Remoting 构架接下来我们考虑通常的情况,也就是 客户程序 与 宿主程序 位于不同的进程中的情况。NOTE:因为我是在我本地机器做的测试,所以只是位于不同进程,实际上位于不同机器中的操作是完全一样的,仅仅是Uri不同,下面将会看到。Remoting 是.Net Framework的一个组成部分,作为一个框架(Framework),两个必备的特性是 基本实现 和 可扩展(可定

996

【本体】Protege高效批量导入实例(Individuals)的自动化实践

本文详细介绍了在Protege中高效批量导入实例(Individuals)的自动化实践方法。通过分析Protege本体文件结构,提供Python脚本示例,帮助用户快速处理大规模数据导入,显著提升知识图谱构建效率。特别适合需要处理数千个实例的医疗、制药等领域应用。

weixin_30275415的博客 408

基于PLC的茶叶揉捻机自动控制系统设计【附代码】

茶叶揉捻是初茶加工过程中的一道关键工序,通过揉捻可以使鲜茶叶成条、碎茶及叶组织细胞破损等。影响茶叶成条率、碎茶率和叶组织细胞破损的主要因素包括揉捻时间、压力和揉捻桶转速。为了提高茶叶品质的稳定性和减轻工人的劳动强度,本文提出了一种基于PLC自动控制技术的茶叶揉捻机控制系统设计。📊 PLC自动化设计 | 毕业设计指导 | 工业自动化解决方案。✅ 具体问题可以私信或查看文章底部二维码。✅ 感恩科研路上每一位志同道合的伙伴!

lagougongzuoshi的博客 1341

远程方法回调(.Net Remoting学习四)

1.应用程序域(.Net Remoting学习一) 2.基本操作(.Net Remoting学习二) 3.分离服务程序实现(.Net Remoting学习三) 4.远程方法回调(.Net Remoting学习四)         Remoting中的方法回调 1. 远程回调方式说明 远程方法回调通常有两种方式: 客户端也存在继承自MarshalByValueObject的

行游客的专栏 1466

使用Tansformer分割三维腹部多器官--UNETR实战

不会 transformer 没关系,本教程开箱即用。Tina姐总算对transformer下手了,之前觉得难,因为刚开始学序列模型的时候就没学会。然后就一直排斥学transformer。这两周没什么事,加上MONAI有现成的教程,就打算先跑通后,再学理论。然后,顺利的跑通了代码,再学了一周理论,发现它也不过如此嘛,入门还是很容易的。有同学想了解的transformer的话,可以先看完这个实战教程,如果感兴趣,后续会出一个transformer入门路线。利用纯Transformers作为编码器来学习输入量的

Tina姐的博客 1万+

.Net Remoting(远程方法回调)

Remoting中的方法回调 1. 远程回调方式说明 远程方法回调通常有两种方式: 客户端也存在继承自MarshalByValueObject的类型,并将该类型的实例作为参数传递给了远程对象的方法,然后远程对象在其方法中通过该类型实例的引用对它进行调用(访问其属性或者方法)。记得继承自MarshalByValueObject的类型实例永远不会离开自己的应用程序域,所以相当于服务端对象调用

738

开题报告该怎么写

考研即将来临,而一般很多大学都会选择在考研结束之后开始安排选题和开题报考(考研之前一般都不谈,老师也很人性化的,不愿意耽误你的复习) 但无论怎么推迟,我们最终都需要去面对并完成这些任务。 现在我就要教大家该如何写一个完整的开题报告! 准备模板。不同的学校有不同的格式,一般情况你的导师会给你们一个学校的标准格式,这个不用太费心。有了模板我们就可以按照模板的“线索”一步一步填充完成即可! 一般大致格式可谓: 研究背景/论文的目的、背景和意义 我们需要写明选择该题目的...

wuyueweifeng的博客 1095

计算文本相似度的常用算法

NLP、数据挖掘领域中,文本分析是一个很重要的领域,这有助于我们去让计算机理解语言的作用和使用。文本分析是数据挖掘的重要手段,利用文本分析,我们将很快的读取到一本书、一篇文章、一段话中的关键词和核心思想,而文本相似度就是我们用来剔除无用信息或者重复信息的重要手段,让计算机去找文本中的不同。 在生活中,信息检索、数据挖掘、机器翻译、文档复制检测等领域都应用到“文本相似度”。文本不仅仅是文字,文本相似度的应用更广,除了文字的匹配,还可以是图片、音频等,因为它们的实质都是在计算机中都是以二进制的方式存在的。相.

氧小氢的博客 2万+

.Net Remoting(远程方法回调) - Part.4

.Net Remoting(远程方法回调) - Part.4 Remoting中的方法回调 1. 远程回调方式说明 远程方法回调通常有两种方式: 客户端也存在继承自MarshalByValueObject的类型,并将该类型的实例作为参数传递给了远程对象的方法,然后远程对象在其方法中通过该类型实例的引用对它进行调用(访问其属性或者方法)。记得继承自MarshalByValueObje...

weixin_34403693的博客 121

coreldraw sp2精简版 x4_CorelDRAW X4下载-CorelDRAW X4 SP2 精简版_Win10镜像官网

CorelDRAW X4 SP2是一个专业图形设计软件,专用于矢量图形编辑与排版,借助其丰富的内容和专业图形设计、照片编辑和网站设计软件,您将能够随心所欲地表达自己的风格与创意,轻松创作徽标标志、广告标牌、车身贴和传单、模型绘制、插图描画、排版及分色输出等。CorelDRAW X4 SP2软件特色CorelDraw X4 相比两年前的 CorelDraw X3 加入了大量新特性,总计有50项以上,...

weixin_30346025的博客 8885

.Net Remoting 事件回调 Client 函数方法完整实例: C# 实现控制台网络聊天室 (Console Remoting ChatRoom)...

.Net Remoting 事件回调 Client 函数方法完整实例: C# 实现控制台网络聊天室 (Console Remoting ChatRoom)http://chs.gotdotnet.com/quickstart/howto/doc/Remoting/quickstart.aspx编译时解析对远程对象的客户端引用的三种不同的方法为:1.编译客户端时,编译服务器对象并将 EXE 或 DL...

weixin_33708432的博客 112

YOLOv11【第三章:高阶应用与落地篇·第7节】多任务联合训练(Multi-Task Learning):检测+分割+关键点三头并进!

🏆 本文收录于专栏 《YOLOv11实战:从入门到深度优化》。本专栏围绕 YOLOv11 的改进、训练、部署与工程优化 展开,系统梳理并复现当前主流的 YOLOv11 实战案例与优化方案,内容目前已覆盖 分类、检测、分割、追踪、关键点、OBB 检测 等多个方向。

**My Coding Family** 727

深度解析:Android开发工程师(嵌入式系统方向)职位 - 技术需求、面试准备与发展路径

本文深入分析了嵌入式Android开发工程师的岗位要求和技术内涵。该职位需要掌握C/C++、Linux系统编程、硬件接口等核心技术,能够进行Android系统底层定制开发,包括HAL层实现、Framework修改、性能优化等工作。文章详细解读了岗位职责,梳理了必备技术栈,提供了针对性的面试问题与参考答案,并探讨了职业发展路径。这类岗位要求开发者兼具软件工程能力和硬件基础知识,适合在智能电视、机顶盒、车载系统等嵌入式领域发展的技术人员。

郑伟强dev的专栏 132

【转载】在.net remoting中实现事件与回调

第一步:创建服务器端对象; 第二步:创建客户端对象; 第三步:创建服务器端宿主程序; 第四步:创建客户端宿主程序; 下面是具体的解释: Remoting中的方法回调 文章出处 NET Remoting中的事件处理(.NET Framework 2.0)(一) 实例下载 1. 远程回调方式说明 远程方法回调通常有两种方式: 客户端也存在继承自Marsha...

135

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

通过Remoting分布公网上的Server实现对Client的回调

    最近工作中遇到一个Remoting的回调的问题,即Client取得Server注册后对象后调用其函数,并传递一个Delegate参数,以让服务器Callback。这个功能在局域网内测试通过,如果配成公网地址在局域网内也是成功的,但当放到真正的公网环境中就失败了。其中Server和Client都是在各自的局域网内,通过服务器连接公网,服务器都有固定的公网IP地址,并将Server端公网地址的

njdxbzu的专栏 2802

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

上一篇: 给GridView加滚动条同时标题不动
下一篇: 通过应用程序域AppDomain加载和卸载程序集[zz]
msikruby
博客等级 码龄19年 11粉丝 7原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值