专业做律师网站的公司,温州手机网站开发,获取网站访客qq号码代码,学校校园网站使用一、引言 上一篇博文分享了消息队列#xff08;MSMQ#xff09;技术来实现分布式应用#xff0c;在这篇博文继续分享下.NET平台下另一种分布式技术——.NET Remoting。 二、.NET Remoting 介绍 2.1 .NET Remoting简介 .NET REmoting与MSMQ不同#xff0c;它不支持离线可得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中涉及的几个重要概念。 远程对象是运行在服务器端的对象客户端不能直接调用由于.NET Remoting传递的对象是以引用的方式因此所传递的远程对象必须继承MarshalByRefObject类这个类可以使远程对象在.NET Remoting应用通信中使用支持对象的跨域边界访问。远程对象的激活方式在访问服务器端的一个对象实例之前必须通过一个名为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中通道类型: TcpChannelTcp通道使用Tcp协议来跨越.Net Remoting边界来传输序列化的消息流TcpChannel默认使用二进制格式序列化消息对象因此具有更高的传输性能但不提供任何内置的安全功能。HttpChannelHttp通道使用Http协议在客户端和服务器之间发生消息使其在Internet上穿越防火墙来传输序列化的消息流这里准确讲不能说穿越主要是因为防火墙都开放了80端口所以使用Http协议可以穿过防火墙进行数据的传输如果防火墙限制了80端口Http协议也照样不能穿越防火墙。默认情况下HttpChannel使用Soap格式序列化消息对象因此它具有更好的互操作性并且可以使用Http协议中的加密机制来对消息进行加密来保证安全性。因此通常在局域网内我们更多地使用TcpChannel如果要穿越防火墙则使用HttpChannel。IpcChannel进程间通信只使用同一个系统进程之间的通信不需要主机名和端口号。而使用Http通道和Tcp通道都要指定主机名和端口号。自定义通道自定义的传输通道可以使用任何基本的传输协议来进行通信如UDP协议、SMTP协议等。三、利用.NET Remoting技术开发分布式应用三部曲 前面详细介绍了.NET Remoting相关内容下面具体看看如何使用.NET Remoting技术来开发分布式应用程序。开发.NET Remoting应用分三步走。 第一步创建远程对象该对象必须继承MarshalByRefObject对象。具体的示例代码如下 1 namespace RemotingObject2 {3 // 第一步创建远程对象4 // 创建远程对象——必须继承MarshalByRefObject,该类支持对象的跨域边界访问5 public class MyRemotingObject :MarshalByRefObject6 {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 RemotingServerHost9 {
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 RemotingClient5 {6 class Client7 {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 RemotingServerHostByConfig6 {7 class Program8 {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 version1.0 encodingutf-8 ?2 !--服务端App.config的内容--3 configuration4 startup 5 supportedRuntime versionv4.0 sku.NETFramework,Versionv4.5 /6 /startup7 system.runtime.remoting8 application9 service
10 wellknown modeSingleton
11 typeRemotingObject.MyRemotingObject,RemotingObject
12 objectUriMyRemotingObject/
13 /service
14 channels
15 channel port9001 reftcp/
16 channel port9002 refhttp/
17 channel portNameIpcTest refipc/ !--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 RemotingClientByConfig6 {7 class Program8 {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 version1.0 encodingutf-8 ?2 configuration3 startup 4 supportedRuntime versionv4.0 sku.NETFramework,Versionv4.5 /5 /startup6 system.runtime.remoting7 application8 client9 wellknown typeRemotingObject.MyRemotingObject,RemotingObject
10 urlhttp://localhost:9002/MyRemotingObject /
11 /client
12 channels
13 channel reftcp port0/channel
14 channel refhttp port0/channel
15 channel refipc port0/channel
16 /channels
17 /application
18 /system.runtime.remoting
19 /configuration 使用配置文件修改后的分布式程序的运行结果与前面的运行结果一样这里就不一一贴图了。 五、总结 到这里.NET Remoting技术的分享就结束了本文只是对.NET Remoting技术做了一个基本的介绍如果想深入了解.NET Remoting技术的话推荐大家可以看看下面的专题细细品味C#——.Net Remoting专题。在下一篇文章中继续为大家分享另一种分布式技术——Web Service。 本文的示例代码文件下载.NETRemotingSample