跟我一起学WCF(2)——利用.NET Remoting技术开发分布式应用

一、引言

   上一篇博文分享了消息队列(MSMQ)技术来实现分布式应用,在这篇博文继续分享下.NET平台下另一种分布式技术——.NET Remoting。

二、.NET Remoting 介绍

2.1 .NET Remoting简介

   .NET REmoting与MSMQ不同,它不支持离线可得,另外只适合.NET平台的程序进行通信。它提供了一种允许对象通过应用程序域与另一个对象进行交互的框架。.NET 应用程序都在一个主应用程序域中执行的,在一个应用程序域中的代码不能访问另一个应用程序域的数据,然而在某些情况下,我们需要跨应用程序域,与另外的应用程序域进行通信,这时候就可以采用.NET Remoting技术来实现与另一个程序域中的对象进行交互。

2.2 .NET Remoting基本原理

   .NET Remoting技术是通过通道来实现两个应用程序之间对象的通信的。首先,客户端通过Remoting技术,访问通道来获得服务器端对象,再通过代理解析为客户端对象,也称作透明代理,此时获得客户端对象只是服务器对象的一个引用。这既保证了客户端和服务端有关对象的松散耦合,同时优化了通信的性能。在这个过程中,当客户端通过透明代理来调用远程对象的方法时,此时会将调用封装到一个消息对象中,该消息对象包括远程对象信息,被调用的方法名和参数,然后透明代理会将调用委托给真实代理(RealProxy对象)的Invoke方法来生成一个IMethodCallMessage,接着通过序列化把这个消息对象序列化成数据流发送到通道,通道会把数据流传送到服务器端。当服务器接收到经过格式化的数据之后,首先从中通过反序列化来还原消息对象,之后在服务器端来激活远程对象,并调用对应的方法,而方法的返回结果过程则是按照之前的方法反向重复一遍,具体的实现原理图如下所示:

2.3 .NET Remoting几个重要概念

   上面简单介绍了下.NET Remoting实现分布式应用程序的基本原理,这里介绍下在.NET Remoting中涉及的几个重要概念。

  1. 远程对象:是运行在服务器端的对象,客户端不能直接调用,由于.NET Remoting传递的对象是以引用的方式,因此所传递的远程对象必须继承MarshalByRefObject类,这个类可以使远程对象在.NET Remoting应用通信中使用,支持对象的跨域边界访问。
  2. 远程对象的激活方式:在访问服务器端的一个对象实例之前,必须通过一个名为Activation的进程创建它并进行初始化。这种客户端通过通道来创建远程对象的方式称为对象的激活。在.NET Remoting中,远程对象的激活分为两大类:服务器端激活和客户端激活。
  • 服务器端激活,又叫做WellKnow(知名对象)激活模式,为什么称为知名对象激活模式呢?是因为服务应用程序在激活对象实例之前会在一个众所周知的统一资源标示符(URI)上发布这个类型,然后该服务器进行会为此类型配置一个WellKnow对象,并根据指定的端口或地址来发布对象。.NET Remoting把服务器端激活又分为SingleTon模式和SingleCall模式两种。

  SingleTon模式:此为有状态模式。如果设置为SingleTon激活模式,则.NET Remoting将为所有客户端建立同一个对象实例。当对象处于活动状态时,SingleTon实例会处理所有后来的客户端访问请求,而不管它们是同一个客户端,还是其他客户端。SingleTon实例将在方法调用中一直维护其状态,类似static成员的概念

  SingleCall模式:是一种无状态模式。一旦设置为SingleCall模式,则当客户端调用远程对象的方法时,Remoting会为每一个客户端建立一个远程对象实例,对象实例的销毁则是由GC自动管理。类似实例成员的概念。

  • 客户端激活:与Wellknow模式不同,。NET Remoting在激活每个对象实例的时候,会给每个客户端激活的类型指派一个URI。客户端激活模式一旦获得客户端的请求,将为每一个客户端都建立一个实例引用。SingleCall模式与客户端激活模式的区别有:首先,对象实例创建的时间不同。客户端激活方式是客户一旦发出调用请求就实例化,而SingleCall则要等到调用对象方法时再创建。其次,SingleCall模式激活的对象是无状态的,对象声明周期由GC管理,而客户端激活的对象是有状态的,其生命周期可自定义。第三,两种激活模式在服务器端和客户端实现的方法不一样,尤其是在客户端,SingleCall模式由GetObject()来激活,它调用对象默认的构造函数,而客户端激活模式,则通过CreateInstance()来激活,它可以传递参数,所以可以调用自定义的构造函数来创建实例。

  3. 通道:在.NET Remoting中时通过通道来实现两个应用程序域之间对象的通信。.NET Remoting中包括4中通道类型:

  1. TcpChannel:Tcp通道使用Tcp协议来跨越.Net Remoting边界来传输序列化的消息流,TcpChannel默认使用二进制格式序列化消息对象,因此具有更高的传输性能,但不提供任何内置的安全功能。
  2. HttpChannel:Http通道使用Http协议在客户端和服务器之间发生消息,使其在Internet上穿越防火墙来传输序列化的消息流(这里准确讲不能说穿越,主要是因为防火墙都开放了80端口,所以使用Http协议可以穿过防火墙进行数据的传输,如果防火墙限制了80端口,Http协议也照样不能穿越防火墙)。默认情况下,HttpChannel使用Soap格式序列化消息对象,因此它具有更好的互操作性,并且可以使用Http协议中的加密机制来对消息进行加密来保证安全性。因此,通常在局域网内,我们更多地使用TcpChannel,如果要穿越防火墙,则使用HttpChannel。
  3. IpcChannel:进程间通信,只使用同一个系统进程之间的通信,不需要主机名和端口号。而使用Http通道和Tcp通道都要指定主机名和端口号。
  4. 自定义通道:自定义的传输通道可以使用任何基本的传输协议来进行通信,如UDP协议、SMTP协议等。

三、利用.NET Remoting技术开发分布式应用三部曲

   前面详细介绍了.NET Remoting相关内容,下面具体看看如何使用.NET Remoting技术来开发分布式应用程序。开发.NET Remoting应用分三步走。

第一步:创建远程对象,该对象必须继承MarshalByRefObject对象。具体的示例代码如下:

 1 namespace RemotingObject
 2 {
 3     // 第一步:创建远程对象
 4     // 创建远程对象——必须继承MarshalByRefObject,该类支持对象的跨域边界访问
 5     public class MyRemotingObject :MarshalByRefObject
 6     {
 7         // 用来测试Tcp通道 
 8         public int AddForTcpTest(int a, int b)
 9         {
10             return a + b;
11         }
12 
13         // 用来测试Http通道
14         public int MinusForHttpTest(int a, int b)
15         {
16             return a - b;
17         }
18 
19         // 用来测试IPC通道
20         public int MultipleForIPCTest(int a, int b)
21         {
22             return a * b;
23         }
24     }
25 }

  远程对象分别定义3个方法,目的是为了测试3中不同的通道方式的效果。

第二步:创建服务器端,需要添加System.Runtime.Remoting.dll引用,具体实现代码如下所示:

 1 using System;
 2 using System.Runtime.Remoting;
 3 using System.Runtime.Remoting.Channels;
 4 using System.Runtime.Remoting.Channels.Http;
 5 using System.Runtime.Remoting.Channels.Ipc;
 6 using System.Runtime.Remoting.Channels.Tcp;
 7 
 8 namespace RemotingServerHost
 9 {
10     // 第二步:创建宿主应用程序
11     class Server
12     {
13         static void Main(string[] args)
14         {
15             // 1.创建三种通道
16 
17             // 创建Tcp通道,端口号9001
18             TcpChannel tcpChannel = new TcpChannel(9001);
19             
20             // 创建Http通道,端口号9002
21             HttpChannel httpChannel = new HttpChannel(9002);
22 
23             // 创建IPC通道,端口号9003
24             IpcChannel ipcChannel = new IpcChannel("IpcTest");
25 
26             // 2.注册通道
27             ChannelServices.RegisterChannel(tcpChannel, false);
28             ChannelServices.RegisterChannel(httpChannel, false);
29             ChannelServices.RegisterChannel(ipcChannel, false);
30 
31             // 打印通道信息
32             // 打印Tcp通道的名称
33             Console.WriteLine("The name of the TcpChannel is {0}", tcpChannel.ChannelName);
34             // 打印Tcp通道的优先级
35             Console.WriteLine("The priority of the TcpChannel is {0}", tcpChannel.ChannelPriority);
36 
37             Console.WriteLine("The name of the HttpChannel is {0}", httpChannel.ChannelName);
38             Console.WriteLine("The priority of the httpChannel is {0}", httpChannel.ChannelPriority);
39 
40             Console.WriteLine("The name of the IpcChannel is {0}", ipcChannel.ChannelName);
41             Console.WriteLine("The priority of the IpcChannel is {0}", ipcChannel.ChannelPriority);
42 
43             // 3. 注册对象
44             // 注册MyRemotingObject到.NET Remoting运行库中
45             RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotingObject.MyRemotingObject), "MyRemotingObject", WellKnownObjectMode.Singleton);
46             Console.WriteLine("Press any key to exit");
47             Console.ReadLine();
48         }
49     }
50 }

第三步:创建客户端程序,具体的实现代码如下所示:

 1 using RemotingObject;
 2 using System;
 3 
 4 namespace RemotingClient
 5 {
 6     class Client
 7     {
 8         static void Main(string[] args)
 9         {
10             // 使用Tcp通道得到远程对象
11             //TcpChannel tcpChannel = new TcpChannel();
12             //ChannelServices.RegisterChannel(tcpChannel, false);
13             MyRemotingObject proxyobj1 = Activator.GetObject(typeof(MyRemotingObject), "tcp://localhost:9001/MyRemotingObject") as MyRemotingObject;
14             if (proxyobj1 == null)
15             {
16                 Console.WriteLine("连接TCP服务器失败");
17             }
18 
19             //HttpChannel httpChannel = new HttpChannel();
20             //ChannelServices.RegisterChannel(httpChannel, false);
21             MyRemotingObject proxyobj2 = Activator.GetObject(typeof(MyRemotingObject), "http://localhost:9002/MyRemotingObject") as MyRemotingObject;
22             if (proxyobj2 == null)
23             {
24                 Console.WriteLine("连接Http服务器失败");
25             }
26 
27             //IpcChannel ipcChannel = new IpcChannel();
28             //ChannelServices.RegisterChannel(ipcChannel, false);
29             MyRemotingObject proxyobj3 = Activator.GetObject(typeof(MyRemotingObject), "ipc://IpcTest/MyRemotingObject") as MyRemotingObject;
30             if (proxyobj3 == null)
31             {
32                 Console.WriteLine("连接Ipc服务器失败");
33             }
34             // 输出信息
35             Console.WriteLine("This call object by TcpChannel, 100 + 200 = {0}", proxyobj1.AddForTcpTest(100, 200));
36             Console.WriteLine("This call object by HttpChannel, 100 - 200 = {0}", proxyobj2.MinusForHttpTest(100, 200));
37             Console.WriteLine("This call object by IpcChannel, 100 * 200 = {0}", proxyobj1.MultipleForIPCTest(100, 200));
38             Console.WriteLine("Press any key to exit!");
39             Console.ReadLine();
40         }
41     }
42 }

  经过上面的三步,我们就完成了这个分布式应用的开发工作,下面测试下该程序是否可以正常运行,首先,运行服务器端,你将看到如下界面:

  在.NET Remoting中,是允许同时创建多个通道的,但是.NET Remoting要求通道的名字必须不同,因为名字是用来标识通道的唯一标识符。但上面代码中,我们并没有指明通道的名字,为什么还可以允许成功呢?从上面图片可知,当我们创建通道时,如果没有为其显式指定通道名,则会使用对应的通道类型作为该通道名,如TcpChannel将会以tcp作为通道名,如果想注册多个Tcp通道则必须显式指定其名字。

  下面看看运行客户端所获得的结果,具体客户端运行效果如下图所示:

 四、使用配置文件来重写上面的分布式程序

  在第三部分中,我们是把服务器的各种通道方式和地址写死在程序中的,这样的实现方式部署起来不方便,下面使用配置文件的方式来配置服务器端的通道类型和服务器地址。  远程对象的定义不需要改变,下面直接看服务器端使用配置文件后的实现代码如下所示:

 1 using System;
 2 using System.Runtime.Remoting;
 3 using System.Runtime.Remoting.Channels;
 4 
 5 namespace RemotingServerHostByConfig
 6 {
 7     class Program
 8     {
 9         static void Main(string[] args)
10         {
11             RemotingConfiguration.Configure("RemotingServerHostByConfig.exe.config", false);
12 
13             foreach (var channel in ChannelServices.RegisteredChannels)
14             {
15                 // 打印通道的名称
16                 Console.WriteLine("The name of the Channel is {0}", channel.ChannelName);
17                 // 打印通道的优先级
18                 Console.WriteLine("The priority of the Channel is {0}", channel.ChannelPriority);
19             }
20             Console.WriteLine("按任意键退出……");
21             Console.ReadLine();
22         }
23     }
24 }

  服务端的配置文件的内容为:

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <!--服务端App.config的内容-->
 3 <configuration>
 4     <startup> 
 5         <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
 6     </startup>
 7   <system.runtime.remoting>
 8     <application>
 9       <service>
10         <wellknown  mode="Singleton"
11                     type="RemotingObject.MyRemotingObject,RemotingObject"
12                     objectUri="MyRemotingObject"/>
13       </service>
14       <channels>
15         <channel port="9001" ref="tcp"/>
16         <channel port="9002" ref="http"/>
17         <channel portName="IpcTest" ref="ipc"/> <!--Ipc通道不需要端口号-->
18       </channels>
19     </application>
20   </system.runtime.remoting>
21 </configuration>

  此时,客户端程序的实现代码如下所示:

 1 using RemotingObject;
 2 using System;
 3 using System.Runtime.Remoting;
 4 
 5 namespace RemotingClientByConfig
 6 {
 7     class Program
 8     {
 9         static void Main(string[] args)
10         {
11             //使用HTTP通道得到远程对象
12             RemotingConfiguration.Configure("RemotingClientByConfig.exe.config", false);
13             MyRemotingObject proxyobj1 = new MyRemotingObject();
14             if (proxyobj1 == null)
15             {
16                 Console.WriteLine("连接服务器失败");
17             }
18 
19             Console.WriteLine("This call object by TcpChannel, 100 + 200 = {0}", proxyobj1.AddForTcpTest(100, 200));
20             Console.WriteLine("This call object by HttpChannel, 100 - 200 = {0}", proxyobj1.MinusForHttpTest(100, 200));
21             Console.WriteLine("This call object by IpcChannel, 100 * 200 = {0}", proxyobj1.MultipleForIPCTest(100, 200));
22             Console.WriteLine("Press any key to exit!");
23             Console.ReadLine();
24         }
25     }
26 }

  客户端配置文件为:

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <configuration>
 3     <startup> 
 4         <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
 5     </startup>
 6   <system.runtime.remoting>
 7     <application>
 8       <client>
 9         <wellknown  type="RemotingObject.MyRemotingObject,RemotingObject"
10                     url="http://localhost:9002/MyRemotingObject" />
11       </client>
12       <channels>    
13         <channel ref="tcp" port="0"></channel>
14         <channel ref="http" port="0"></channel>
15         <channel ref="ipc" port="0"></channel>
16       </channels>
17     </application>
18   </system.runtime.remoting>
19 </configuration>

  使用配置文件修改后的分布式程序的运行结果与前面的运行结果一样,这里就不一一贴图了。

五、总结

   到这里,.NET Remoting技术的分享就结束了,本文只是对.NET Remoting技术做了一个基本的介绍,如果想深入了解.NET Remoting技术的话,推荐大家可以看看下面的专题细细品味C#——.Net Remoting专题。在下一篇文章中,继续为大家分享另一种分布式技术——Web Service。

   本文的示例代码文件下载:.NETRemotingSample

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/276326.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二叉树的建立与遍历_51、二叉树遍历-重建二叉树JZ4

题目描述输入某二叉树的前序遍历和中序遍历的结果&#xff0c;请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}&#xff0c;则重建二叉树并返回。思路回顾三种经典的遍历&…

推荐关注这7个高质量的前端公众号

拓宽眼界&#xff0c;增加深度&#xff0c;在阅读的世界里&#xff0c;我们往往能找到不一样的态度&#xff0c;提升朋友圈质量&#xff0c;从关注这几个公众号开始。轻扫一下二维码就行了&#xff0c;你可以试试&#xff0c;肯定会有意外收获。大迁世界 简介&#xff1a;前端小…

Windows Live Writer 在win2003 的安装方法

下载Windows Live Writer整体安装包&#xff0c;最好是离线安装包 2.在xp系统上安装 3.查找C:\Program Files\Common Files\Windows Live\.cache目录 .cache目录是隐藏的&#xff0c;目录下面就是各个安装文件的msi安装包 4.拷贝相应的msi文件&#xff0c;到Windows 2003安装就…

decode 大于比较 小于_6 燃气输配系统6.3 压力不大于1.6Mpa的室外燃气管道城镇燃气设计规范 GB500282006(2020修订版)...

6.3 压力不大于1.6Mpa的室外燃气管道6.3.1中压和低压燃气管道宜采用聚乙烯管、机械接口球墨铸铁管、钢管或钢骨架聚乙烯塑料复合管&#xff0c;并应符合下列要求&#xff1a; 1 聚乙烯燃气管应符合现行的国家标准《燃气用埋地聚乙烯管材》GB15558.1 和《燃气用埋地聚乙烯管件…

若川的2017年度总结,一如既往

可以点击上方的标签若川的故事、年度总结&#xff0c;查看往期文章有读者反馈说看我年度总结系列比我源码系列更有启发。所以打算把2016-2018的年度总结发布到公众号声明原创&#xff0c;希望对大家有所启发。&#xff08;虽然我的每一年都过得非常普通...&#xff09;若川的20…

沟通:用故事产生共鸣

《沟通:用故事产生共鸣》(全彩) 基本信息作者&#xff1a; Nancy Duarte(南希.杜瓦特)译者&#xff1a; 冯海洋出版社&#xff1a;电子工业出版社ISBN&#xff1a;9787121195914上架时间&#xff1a;2013-4-1出版日期&#xff1a;2013 年3月开本&#xff1a;12开页码&#xff1…

若川的2018年度总结,平淡无奇

可以点击上方的标签若川的故事、年度总结&#xff0c;查看往期文章偷偷告诉你&#xff0c;公众号内回复【报告】&#xff0c;可以获取你自己的github 2020 年度报告昨晚在我的6个微信群里都发了红包&#xff0c;以这样的方式跨过了2020年。运营公众号真的挺难的&#xff0c;比如…

基于dnn的车牌识别_自然场景中文文字识别,身份证火车票都能识别

图像处理中OCR(Optical Character Recognition光学字符识别)场景非常多&#xff0c;也给大家的工作生活带来了很多便利&#xff0c;比如车牌识别就能管理停车场车辆的出入&#xff0c;快递时只需给一个带有快递信息的图就能自动解析上传发件信息和收件信息&#xff0c;再比如我…

年末的大厂前端面试总结(20届双非二本)-终入字节

关注若川视野, 回复"pdf" 领取资料&#xff0c;回复"1"&#xff0c;可加群长期交流学习自我介绍双非二本,软件工程,自学前端,今年毕业。喜欢编程,古风,日语和英语。常以冷月心之名混迹前端江湖,也曾在混迹网文圈时用冷月心做笔名签约掌阅,作品《清起风云》…

动图演示23个鲜为人知的VSCode快捷键

原文地址&#xff1a;https://dev.to/devmount/23-lesser-known-vs-code-shortcuts-as-gif-80尽管我在VS Code中经常使用许多快捷方式&#xff0c;以下快捷方式可能会派上用场&#xff0c;但我经常忘记它们的存在。我制作了一些GIF&#xff0c;以便更好地记住它们。也许这里面也…

使用C语言进行面向对象的开发--GObject入门[5]

转载请注明出处 blog.csdn.net/pingf0 或www.cnblogs.com/pingf 接上文这一部分简要介绍下类的析构&#xff0c;或者成为终结。还是多说几句&#xff0c;也算是对前文的补充1.生成一个类是由父到子&#xff0c;析构的时候自然与之相对是由子到父。2.GObject的内存管理并没有采用…

面试官问:能否模拟实现JS的bind方法(高频考点)

可以点击上方的话题JS基础系列&#xff0c;查看往期文章写于2018年11月21日&#xff0c;发布在掘金阅读量1.3w前言这是面试官问系列的第二篇&#xff0c;旨在帮助读者提升JS基础知识&#xff0c;包含new、call、apply、this、继承相关知识。面试官问系列文章如下&#xff1a;感…

连续投影算法_中航国画荣获“2020 IAV国际视听嘉年华” 大屏幕投影显示行业三大奖项!...

近日&#xff0c;“2020IAV国际视听嘉年华”在深圳湾创新生态园隆重举行&#xff0c;航空工业上电下属子公司中航国画作为2020年迪拜世博会中国馆官方合作伙伴应邀参加此次高峰论坛&#xff0c;并在展会期间凭借4K系列双色激光工程投影机、LP160UL系列超高亮度双色激光工程投影…

CMDB功能分析与实现方案

CMDB功能分析与实现方案 CMDB系统的主要功能 1.用户管理,记录测试,开发,运维人员的用户表 2.业务线管理,记录业务的详情 3.项目管理,指定此项目属于那一条业务线 4.应用管理,指定此应用的开发人员 5.主机管理,记录主机管理员,连接的网络设备,存储,云主机,物理主机等信息 6.主机…

他的前端焦虑:30岁以后的前端路怎么走? 你想过吗~

马云曾说&#xff0c;员工的离职原因很多&#xff0c;唯两点最真实&#xff1a;一是钱&#xff0c;没给到位&#xff1b;二是心&#xff0c;委屈了。当时间来到了年末&#xff0c;离职、跳槽、年终奖又成了年终热词&#xff0c;而此时辞职好似成为了一场勇敢者的游戏&#xff0…

码云 Gitee 新增仓库访问之 IP 白名单功能

码云企业版上线 IP 白名单功能&#xff0c;该功能主要用于企业禁止非指定 IP 访问代码仓库。如下图所示&#xff1a;使用方法&#xff1a;进入企业控制面板 -> 管理 -> 安全设置添加允许访问 Git 仓库的 IP 地址启用安全选项&#xff1a;只允许在信任范围内推拉代码其他关…

福利 | 抽奖送现金送书《Web前端工程师修炼之道》

很多关注了我的公众号的粉丝可能都不知道我&#xff0c;趁这次机会简单介绍下。你好&#xff0c;我是若川。江西人&#xff0c;某不那么知名的陶瓷大学毕业生&#xff0c;目前在杭州从事前端开发工作。常以若川为名混迹于江湖。更详细的可以点击关于我我历时一年才写了《学习源…

蒙特卡洛方法_基本理论-蒙特卡洛方法与定积分

全球图形学领域教育的领先者、自研引擎的倡导者、底层技术研究领域的技术公开者&#xff0c;东汉书院在致力于使得更多人群具备内核级竞争力的道路上&#xff0c;将带给小伙伴们更多的公开技术教学和视频&#xff0c;感谢一路以来有你的支持。我们正在用实际行动来帮助小伙伴们…

字节面试官:如何实现Ajax并发请求控制

偷偷告诉你&#xff0c;点此抽奖送红包还送3本比红宝书还贵的书实现一个批量请求函数 multiRequest(urls, maxNum)&#xff0c;要求如下&#xff1a; • 要求最大并发数 maxNum • 每当有一个请求返回&#xff0c;就留下一个空位&#xff0c;可以增加新的请求 • 所有请求完成后…