如何通过Remoting实现双向通信

简介:

Remoting是NET平台下比较成熟高效的分布式技术,我们习惯采用传统的远程调用的方式使用Remoting。在客户端所在的Application Domain,我们通过Proxy(Transparent Proxy)远程地跨Application Domain调用一个方法。当来自Client端的调用请求通过Proxy到达Server端所在的Application Domain后,Remoting Infrastructure在Server 端激活(Activate)相应的远程对象(一个继承子System.MarshalByRefObject类对象)——这里仅仅以服务端激活对象(Server Activated Object——SAO),然后再Server端执行相应的操作后把Result传递给Proxy,并最终到达Client。这是一种典型的Request/Response的调用方式。

我之所以一直比较推崇在.NET平台下使用Remoting而非XML Web Service是因为我觉得.NET Remoting是一种比较成熟的分布式技术。它自身提供了XML Web Service很多不具备的特性,其中对双向通信的支持就是一个很好的体现。

相对于典型的Request/Response的消息交换模式(Message Exchange Pattern——MEP),双向通信实质上是采用的Duplex的MEP。也就是说,Server端在执行操作的时候,可以回调(Callback)Client端的操作(这个操作时再Client端的Application Domain中执行的)。

现在我们来看如何一步一步实现在Remoting环境下的双向通信。在下面的Sample中,我们的逻辑是:调用一个数学计算的远程调用,除了传递相应的操作数之外,我们还传递一个对象,这个对象可以在Server端中回调 (Callback) 把运算结果在Client端显示出来。可以通过下面的URL下载源代码:http://www.cnblogs.com/files/artech/Artech.DuplexRemoting.zip
步骤一、构建整个Solution的整体构架

  • Artech.DuplexRemoting.Contract:Class Library Project,定义远程对象(Remote Object)和Callback对象的Contract(Interface)。实际上,站在Server端的角度上看,Callback的操作是在Client端的Application Domain中执行的,所以从本质上讲, Callback对象是Server端的远程对象。之所以定义这样一个Contract Project,其目的主要有以下两点:

如果没有把远程对象的Interface,对已某一个需要调用这个远程对象的Client来说,它必须引用远程对象本身。从安全的角度考虑,Server向Client过多暴露了操作的实现逻辑。如果我们把远程操作的Contract提取出来,Client只要引用这个Interface就可以了。

一般来说,远程对象的Contract相对时静态的(static),而业务逻辑的实现则是经常 变化的。因为Client只需要了解的是远程对象的Contract,所在无论Server端对远程对象的实现作了多大的变动,对不回对Client产生任何影响。

  • Artech.DuplexRemoting.Remoting:Class Library Project,定义远程对象本身。由于远程对象必须实现上边定义的Contract。所以需要引用Artech.DuplexRemoting.Contract。
  • Artech.DuplexRemoting.Hosting:Console Application Project,以Self-Host的方式Host Remoting。引用Artech.DuplexRemoting.Remoting。
  • Artech.DuplexRemoting.Client:Console Application Project,引用Artech.DuplexRemoting.Contract。

步骤二、定义Contract

IDuplexCalculator

   1: public interface IDuplexCalculator
   2: {
   3:     void Add(double x, double y, ICalculatorCallback callback);
   4: }

ICalculatorCallback

   1: public interface ICalculatorCallback
   2: {
   3:       void ShowResult(double x, double y, double result);
   4: }

步骤三、定义远程对象类型

DuplexCalculatorRemoting

   1: public class DuplexCalculatorRemoting : MarshalByRefObject, IDuplexCalculator
   2: {
   3:     public void Add(double x, double y, ICalculatorCallback callback)
   4:     {
   5:         Console.WriteLine("Invoke the method Add({0},{1}).", x, y);
   6:         double result = x + y;
   7:         callback.ShowResult(x, y, result);
   8:     }
   9: }

步骤四、Host远程对象

App.config

   1: <configuration>
   2:     <system.runtime.remoting>
   3:         <application name="Calculator">
   4:             <service>            
   5:                 <wellknown mode="SingleCall"
   6:                            type="Artech.DuplexRemoting.Remoting.DuplexCalculatorRemoting,Artech.DuplexRemoting.Remoting"
   7:                            objectUri="DuplexCalculator.soap" />
   8:             </service>
   9:  
  10:             <channels>
  11:                 <channel ref="http" port="8080">
  12:                     <serverProviders>
  13:                         <provider ref="wsdl" />
  14:                         <formatter ref="binary" typeFilterLevel="Full" />
  15:                     </serverProviders>
  16:                     <clientProviders>
  17:                         <formatter ref="binary" />
  18:                     </clientProviders>
  19:                 </channel>
  20:             </channels>
  21:         </application>
  22:     </system.runtime.remoting>
  23: </configuration>

Program.cs

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         System.Runtime.Remoting.RemotingConfiguration.Configure("Artech.DuplexRemoting.Hosting.exe.config",false);
   6:         Console.WriteLine("Calculator service has begun to listen ");
   7:         Console.Read();
   8:     }
   9: }

这里需要特别注意的有以下两点:

  • 在定义Channel是需要指定一个双向Channel(Bi-Directional Channel)。系统给我们定义一一系列的System-Defined Channel用于调用远程对象。其中有一些只能提供单向的通信——比如只支持Client到Server的通信,而另一些可以提供双向的通信——比如TCP Channel 和Http Channel.
  • 在ServerProvider Section,我们必须设置typeFilterLevel为Full。出于安全的考量,Remoting提供了两个反序列化级别(Level)——Low & Full。Low是默认的,如果把typeFilterLevel设为Low,Remoting之会反序列化Remoting基本功能相关的对象。而设为Full则意味着 Remoting 会反序列化所有类型。如果你想知道那些类型是在 Low Level 下被限制,请参考 http://msdn2.microsoft.com/en-us/library/5dxse167.aspx

之所以要把typeFilterLevelFull,是因为我们的远程调用里包含一Callback对象,它实际上是一个继承System.MarshalByRefObject类对象(这个的对象将在Artech.DuplexRemoting.Client中定义)。而这个对象是不会再Low Level下被自动反序列化。

   1: <channels>
   2:   <channel ref="http" port="8080">
   3:     <serverProviders>
   4:       <provider ref="wsdl" />
   5:       <formatter ref="binary" typeFilterLevel="Full" />
   6:     </serverProviders>
   7:     <clientProviders>
   8:       <formatter ref="binary" />
   9:     </clientProviders>
  10:   </channel>
  11: </channels>

   1: public interface IDuplexCalculator
   2: {
   3:      void Add(double x, double y, ICalculatorCallback callback);
   4: }

步骤五、定义Callback对象类型和调用远程对象

CalculatorCallbackHandler

   1: public class CalculatorCallbackHandler : MarshalByRefObject, ICalculatorCallback
   2: {
   3:     public void ShowResult(double x, double y, double result)
   4:     {
   5:         Console.WriteLine("x + y = {2} where x = {0} and y = {1}", x, y, result);
   6:     }
   7: }

App.config

   1: <configuration>
   2: <system.runtime.remoting>
   3:     <application>
   4:         <channels>
   5:             <channel ref="http" port="0">
   6:                 <clientProviders>
   7:                     <formatter ref="binary" />
   8:                 </clientProviders>
   9:                 <serverProviders>
  10:                     <formatter ref="binary" typeFilterLevel="Full" />
  11:                 </serverProviders>
  12:             </channel>
  13:         </channels>        
  14:     </application>
  15: </system.runtime.remoting>
  16: </configuration>

Program.cs

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         System.Runtime.Remoting.RemotingConfiguration.Configure("Artech.DuplexRemoting.Client.exe.config", false);
   6:  
   7:         InvocateDuplexCalculator("http://localhost:8080/Calculator/DuplexCalculator.soap");
   8:     }
   9:  
  10:     static void InvocateDuplexCalculator(string remoteAddress)
  11:     {
  12:         IDuplexCalculator proxy = (IDuplexCalculator)Activator.GetObject(typeof(IDuplexCalculator), remoteAddress);
  13:         proxy.Add(1, 2, new CalculatorCallbackHandler());
  14:         Console.Read();
  15:     }
  16: }

这里有两点需特别注意的:

  • 由于Server端时跨Application Domain远程地调用运行Client Application Domain中的Callback对象(Callback的执行实际是在Client而不在Server),所以Callback对象应该是一个MarshalByRefObject对象;
  • 上面我们以经提及,对于 Server 端了来说 Callback 对象实际上是一个远程对象(在 Callback 过程中 Client 端转变成 Server 端,而 Server 端转变成 Client 端)。 Server 端需要注册一些 Channel 用于 Client 访问寄宿在 Server 端的远程对象,同理, Server 需要 Callback 一个寄宿在 Client Application Domain 中的 Callback 对象, Client 端需要注册相应的 Channel;
  • Server 端一样,我们必须设置 typeFilterLevel Full  

到现在为止我们已经完成了所有的Program,我们来运行一下,在客户端你将得到如下的输出:

   1: x + y = 3 where x = 1 and y = 2

步骤六、将远程对象Host到IIS中

我们知道,Remoting有两种Host方式Self HostIIS Host,上面我们把Remoting Host到一个Console Application中; 现在我们把试着把它HostIIS中。实际上我们要做的工作很简单。

  • IIS Manager中添加一个虚拟目录对应Artech.DuplexRemoting.Remoting文件夹, 假设此虚拟目录的AliasArtech.DuplexRemoting
  • Artech.DuplexRemoting.Remoting根目录下中(也就是在http://localhost/Artech.DuplexRemoting根目录下)添加一个Web.config,并添加类似于Artech.DuplexRemoting.Hosting/App.Config Remoting Configuration

   1: <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
   2:   <system.runtime.remoting>
   3:     <application>
   4:       <service>
   5:         <wellknown mode="SingleCall"
   6:                    type="Artech.DuplexRemoting.Remoting.DuplexCalculatorRemoting,Artech.DuplexRemoting.Remoting"
   7:                    objectUri="DuplexCalculator.soap" />
   8:       </service>
   9:       <channels>
  10:         <channel ref="http">
  11:           <serverProviders>
  12:             <provider ref="wsdl" />
  13:             <formatter ref="binary" typeFilterLevel="Full" />
  14:           </serverProviders>
  15:           <clientProviders>
  16:             <formatter ref="binary" />
  17:           </clientProviders>
  18:         </channel>
  19:       </channels>
  20:     </application>
  21:   </system.runtime.remoting>
  22: </configuration>

这样我们可以不需要Hosting,就可以运行Client了。

我所理解的.NET Remoting:
我所理解的Remoting(1):Marshaling & Activation - Part I
我所理解的Remoting(1):Marshaling & Activation - Part II
我所理解的Remoting(2):远程对象生命周期的管理—Part I
我所理解的Remoting(2):远程对象的生命周期管理-Part II
我所理解的Remoting(3
):创建CAO Service Factory使接口和实现相互分离


作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
JavaScript Java Maven
|
7月前
|
设计模式 Java 数据库连接
【设计模式】【创建型模式】工厂方法模式(Factory Methods)
一、入门 什么是工厂方法模式? 工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个用于创建对象的接口,但由子类决定实例化哪个类。工厂方法模式使类的实例化延迟
203 16
|
项目管理
「软件项目管理」一文详解软件项目管理概述
该文章详细介绍了软件项目管理的关键概念、知识体系以及实施过程,涵盖了项目初始化、计划制定、执行控制到项目结束的全流程管理,并探讨了项目管理与过程管理在软件开发中的相互作用和应用。
「软件项目管理」一文详解软件项目管理概述
|
监控 网络协议 API
.NET WebSocket 技术深入解析,你学会了吗?
【9月更文挑战第4天】WebSocket 作为一种全双工协议,凭借低延迟和高性能特点,成为实时应用的首选技术。.NET 框架提供了强大的 WebSocket 支持,使实时通信变得简单。本文介绍 WebSocket 的基本概念、.NET 中的使用方法及编程模型,并探讨其在实时聊天、监控、在线游戏和协同编辑等场景的应用,同时分享最佳实践,帮助开发者构建高效实时应用。
393 12
|
移动开发 JavaScript 前端开发
React 还是 Vue: 你应该选择哪一个Web前端框架?
React 还是 Vue: 你应该选择哪一个Web前端框架?
898 0
|
监控 数据库 时序数据库
性能监控之Telegraf+InfluxDB+Grafana window服务器安装使用
【6月更文挑战13天】性能监控之Telegraf+InfluxDB+Grafana window服务器安装使用
826 1
|
消息中间件 负载均衡 监控
基于kafka项目之Keepalived高可用详细介绍
基于kafka项目之Keepalived高可用详细介绍
|
安全 Java 数据库
【开题报告】基于SpringBoot的医美在线预约系统的设计与实现
【开题报告】基于SpringBoot的医美在线预约系统的设计与实现
419 0
|
存储 人工智能 安全
三个故事方法:使用 ChatGPT 编辑你的场景(全)
三个故事方法:使用 ChatGPT 编辑你的场景(全)
435 0
|
API
scroll-view回到顶部功能的实现
在我最近写的一个项目中就有这样的一个需求,即无限滚动卡片列表中实现回到顶部,与已往的返回顶部功能不同,因为是通过scroll-view来实现的无限列表滚动,所以返沪顶部需要依靠scroll-view的一些特定属性和api,下面我将带大家分析,实现这个功能。
739 1
scroll-view回到顶部功能的实现