跟我一起学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;则重建二叉树并返回。思路回顾三种经典的遍历&…

越来越觉得现在的工作很枯燥

很不想这么说&#xff0c;但又不想欺骗自己&#xff0c;真的是很枯燥&#xff0c;不过这种感觉早在一年在在上一间公司时就很强烈的有过这种感觉了&#xff0c;只不过现在是又一次有感触罢了。话说说我这种性质的工作枯燥很多人都讲过&#xff0c;如果哪个人说不枯燥估计脑袋进…

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

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

MySQL 实用语句集合

MySQL 实用语句集合 参考链接[用户]&#xff1a;http://blog.csdn.net/dmtnewtons_blog/article/details/9136339 参考链接[属性]&#xff1a;http://stackoverflow.com/questions/15821532/get-current-auto-increment-value-for-any-table 参考链接[索引]&#xff1a;htt…

python对象序列化或持久化的方法

http://blog.csdn.net/chen_lovelotus/article/details/7233293 一、Python对象持久化方法 目前为止&#xff0c;据我所知&#xff0c;在python中对象持久化有以下几种方法&#xff1a; 1. 使用(dbhash/bsddb, dbm, gdbm, dumbdbm 等&#xff09;以及它们的"管理器"(…

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…

MIME协议及源邮件格式分析

转载链接&#xff1a;http://wenku.baidu.com/view/7246de671ed9ad51f01df277.html 电子邮件也许是一个Internet上的流行最广泛的应用。也是我们现在的大多数网络办公流程的基础。各种邮件服务器很多,但都大都遵循以1982年出版的RFC822--《ARPA网络文本信息格式标准(STANDARD F…

沟通:用故事产生共鸣

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

合工大五套卷_2020合工大超越数一五套卷第一套感想

合工大的卷子确实不错&#xff0c;题目给我的感觉是题干包装的看起来就很难&#xff0c;但是写起来还是一样的套路。计算上要难一些&#xff0c;需要细心点选择题:1.可去间断点的定义和泰勒公式2.这个题我用排除法写的&#xff0c;可微的话连续和偏导存在都成立了&#xff0c;然…

DotNet关键知识点——WPF篇(一)(范德成编辑批注版)

1. Journal 的使用 Journal 用于在 XAML 浏览器应用程序&#xff08;XBAP&#xff09;中维护历史访问页。删除前一访问页只需调当前 NavigationService 对象的 RemoveBackEntry() 即可&#xff1b;而增加一个访问页则复杂得多&#xff1a; 1) 实现一个 CustomContentState 的派…

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

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

Simple TCP Server Client Socket C

转载链接&#xff1a;http://blog.163.com/caipeipei_love126/blog/static/2596603220101118433940/ tcpserver.c #include<stdlib.h> #include<stdio.h> #include<errno.h> #include<string.h> #include<netdb.h> #include<sys/types.h>…

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

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

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

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

面试题(转的)

第一组   1.烧一根不均匀的绳&#xff0c;从头烧到尾总共需要1个小时。现在有若干条材质相同的绳子&#xff0c;问如何用烧绳的方法来计时一个小时十五分钟呢?  2.你有一桶果冻&#xff0c;其中有黄色、绿色、红色三种&#xff0c;闭上眼睛抓取同种颜色的两个。抓取多少个…

python三酷猫_洛克王国三代酷猫登场 冰水酷猫解析

洛克王国三代酷猫登场 冰水酷猫解析 洛克王国三代武斗酷猫解析三代水灵&#xff0c;在哥斯拉的倾情推荐下&#xff0c;小洛克们都已经很熟悉了吧&#xff01;那和水灵同一期出现的帅哥——武斗酷猫&#xff0c;如果三代遗传了&#xff0c;会怎么样呢&#xff1f;小洛克们一起来…

Linux禁止用户登录

转载链接&#xff1a;http://blog.sina.com.cn/s/blog_4cebadd10100a9bl.html 我们在做系统维护的时候&#xff0c;希望个别用户或者所有用户不能登录系统&#xff0c;保证系统在维护期间正常运行。这个时候我们就要禁止用户登录。 1、禁止个别用户登录。比如禁止lynn用户登录…