.Net组件程序设计之远程调用(二)

 .Net组件程序设计之远程调用(二)

激活模式

引用封送对象激活类型两种,

一种是客户端激活类型,一种是服务器端激活.

客户端激活对象   

客户端激活方式:当客户端创建一个远程对象时,客户端得到的是一个新的实例引用,新的实例可以在内存中维持状态,并且可以使用参数化构造函数来激活远程对象。

服务器激活模式single-call    

SingleCall激活方式:当客户端使用一个服务器激活方式为SingleCall的对象时,.NET为每个方法调用创建一个新对象,在方法执行完毕后,对象则被销毁,客户端虽然维持着对远程对象的引用,但是真实对象已经被销毁了。

服务器激活Singleton

Singleton激活方式:所有客户端共享一个远程对象。

下面为大家演示几段示例,就详细的清楚每一种激活方式的作用了。

服务端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  1      using  System.Runtime.Remoting;
  2      using  System.Runtime.Remoting.Messaging;
  3      namespace  RemoteServer
  4      /// <summary>
  5      /// 服务端
  6      /// </summary>
  7      public  class  MyClass : MarshalByRefObject
  8     {
  9          public  MyClass()
10         {
11             _count++;
12              string  mes = AppDomain.CurrentDomain.FriendlyName;
13              Console.WriteLine(mes);
14         }
15 
16          private  int  _count = 0;
17 
18          public  event  EventHandler NumberChanged;
19 
20          public  void  Count()
21         {
22             _count++;
23              Console.WriteLine(AppDomain.CurrentDomain.FriendlyName +  "_"  + _count.ToString());
24         }
25 
26          public  void  OnNumberChanged( int  num)
27         {
28              if  (NumberChanged !=  null )
29             {
30                 NumberChanged(num,  null );
31             }
32         }
33     }
34 
35      public  class  EventMehtodClass : MarshalByRefObject
36     {
37         [OneWay]
38          public  void  OnNumberChanged( object  sender, EventArgs e)
39         {
40              if  (sender !=  null )
41             {
42                  Console.WriteLine(sender.ToString());
43             }
44         }
45     }
2.编程式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  1 宿主服务端(服务器端)
  2              using  System.Runtime.Remoting;
  3              using  System.Runtime.Remoting.Channels;
  4              using  System.Runtime.Remoting.Channels.Http;
  5              using  System.Runtime.Remoting.Channels.Tcp;
  6              using  System.Runtime.Remoting.Channels.Ipc;
  7              using  System.Runtime.Remoting.Services;
  8              using  RemoteServer;
 
10              namespace  RemoteServerHost
11 
12             #region 编程式 宿主服务端注册 信道和对象类型
13             Console.WriteLine( "开始Tcp注册信道" );
14             IChannel tcpChannel =  new  TcpChannel(8003);
15             ChannelServices.RegisterChannel(tcpChannel,  false ); //注册Tcp类型信道
16             Console.WriteLine( "Tcp信道注册完成————————————————" );
17             Console.WriteLine( "开始 服务器激活类型SingleCall模式的宿主服务器端类型注册" );
18             RemotingConfiguration.RegisterWellKnownServiceType( typeof (MyClass),  "RWCTmyclass" ,WellKnownObjectMode.SingleCall);
19             Console.WriteLine( "类型注册完成" );
20             #endregion
21 
22             Thread.Sleep( new  TimeSpan(0, 2, 0));
23             Console.WriteLine( "释放Tcp信道" );
24             ChannelServices.UnregisterChannel(tcpChannel);

这里所用的激活方式是 服务器SingleCall激活方式,通过RemotingConfiguration.RegisterWellKnownServiceType()方法来注册类型,第二个参数为统一资源标识符(URI),很好理解就是字面的意思,远程对象就是资源,标识资源的一个符号(名称),有了它,客户端在调用远程对象的时候才知道具体在哪。因为是服务器激活方式所以URI是在包含在注册类型的方法中的,而如果是客户端激活类型注册的话,则使用RemotingConfiguration.RegisterActivatedServiceType(typeof(MyClass));

有的朋友会问了,这样统一资源标识符不是没设置吗?是的,确实没有设置,客户端激活类型注册的时候URI是这样设置

1
1 RemotingConfiguration.ApplicationName =  "RWCTmyclass" ;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
   1 客户端(调用端)
  2              using  System.Runtime.Remoting;
  3              using  System.Runtime.Remoting.Channels;
  4              using  System.Runtime.Remoting.Channels.Http;
  5              using  System.Runtime.Remoting.Channels.Tcp;
  6              using  System.Runtime.Remoting.Channels.Ipc;
  7              using  System.Runtime.Remoting.Services;
  8              using  RemoteServer;
 
10              namespace  RemoteClient
11 
12             #region 编程式本地注册
13             Thread.Sleep( new  TimeSpan(0, 0, 7)); //便于调,使当前客户端线程阻塞7秒,确保宿主服务端已经运行
14              string  url =  "tcp://localhost:8003/RWCTmyclass" ;
15             Console.WriteLine( "开始客户端注册类型" );
16             RemotingConfiguration.RegisterWellKnownClientType( typeof (MyClass), url);
17             #endregion
18 
19 
20              //类型使用
21             MyClass myclass =  new  MyClass();
22             myclass.Count();
23             MyClass myclass1 =  new  MyClass();
24             myclass1.Count();
图 1

 因为这里使用的是服务器SingleCall类型模式激活的,所以对象状态是不保存的,就跟上面那一小节定义的一样,只有在方法调用的时候才会被创建,方法调用完毕则会被释放销毁,但是也可以在宿主服务端使用变量来记录状态。现在可以在宿主服务端(服务器端)注册类型的时候把激活模式换成Singleton的再来看一下结果:
这是编程式的示例代码,下面给大家演示配置式的。

3.配置式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  1 宿主服务端(服务器端)
  using  System.Runtime.Remoting;
  using  System.Runtime.Remoting.Channels;
  using  System.Runtime.Remoting.Channels.Http;
  using  System.Runtime.Remoting.Channels.Tcp;
  using  System.Runtime.Remoting.Channels.Ipc;
  using  System.Runtime.Remoting.Services;
 
  using  System.Threading;
10 
11  using  RemoteServer;
12 
13  namespace  RemoteServerHost
14 
15             #region 配置式宿主服务端注册 信道和对象类型
16             Console.WriteLine( "开始注册Http信道" );
17             RemotingConfiguration.Configure(AppDomain.CurrentDomain.FriendlyName +  ".config" );
18             Console.WriteLine( "Http信道注册完成————————————————" );
19             #endregion

这里只要使用.NET给我们提供的RemotingConfiguration类型中的Configure()方法来加载配置文件就行了,注册信道的类型,远程对象的激活方式和模式都是在配置文件中注册的,来看配置文件信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
  1 <? xml  version = "1.0"  encoding = "utf-8"  ?>
  2 < configuration >
  3   < system.runtime.remoting >
  4     < application >
  5       < channels >
  6         < channel  ref = "http"  port = "8004" />
  7       </ channels >
  8       < service >
  9         < wellknown  mode = "Singleton"  type = "RemoteServer.MyClass,RemoteServer"  objectUri = "RTMyClass"  />
10       </ service >
11     </ application >
12   </ system.runtime.remoting >
13 </ configuration >

这里配置文件中,是准备注册http类型的信道,并且把远程对象注册为服务器激活类型(wellKnow)Singleton激活模式,宿主服务端的就这么多,接下来看客户端的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  1 客户端
  using  System.Runtime.Remoting;
  using  System.Runtime.Remoting.Channels;
  using  System.Runtime.Remoting.Channels.Http;
  using  System.Runtime.Remoting.Channels.Tcp;
  using  System.Runtime.Remoting.Channels.Ipc;
  using  System.Runtime.Remoting.Services;
 
  using  System.Threading;
10 
11  using  RemoteServer;
12 
13  namespace  RemoteClient
14 
15             #region 配置式本地注册
16             Thread.Sleep( new  TimeSpan(0, 0, 7));
17             Console.WriteLine( "开始客户端注册类型" );
18             RemotingConfiguration.Configure(AppDomain.CurrentDomain.FriendlyName +  ".config" false );
19             #endregion
20              //类型使用
21             Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
22             MyClass myclass =  new  MyClass();
23             myclass.Count();
24             MyClass myclass1 =  new  MyClass();
25             myclass1.Count();

跟宿主服务端的一样,使用Configure()方法来注册远程对象,但是本地的配置文件怎么配置呢?不着急的,一起来看:

1
2
3
4
5
6
7
8
9
10
  1 <?xml version= "1.0"  encoding= "utf-8"  ?>
  2 <configuration>
  3   <system.runtime.remoting>
  4     <application>
  5       <client>
  6         <wellknown type= "RemoteServer.MyClass,RemoteServer"  url= "http://localhost:8004/RTMyClass" />
  7       </client>
  8     </application>
  9   </system.runtime.remoting>
10 </configuration>

客户端 要注册的 远程对象类型 的 激活类型(客户端激活、服务器端激活) 是要跟宿主服务端的相对应。
这次换了Singleton模式

图2

4.远程回调
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  1 宿主服务端:
  2          using  System.Runtime.Remoting;
  3          using  System.Runtime.Remoting.Channels;
  4          using  System.Runtime.Remoting.Channels.Http;
  5          using  System.Runtime.Remoting.Channels.Tcp;
  6          using  System.Runtime.Remoting.Channels.Ipc;
  7          using  System.Runtime.Remoting.Services;
  8          using  System.Threading;
  9         
10          using  RemoteServer;
11          namespace  RemoteServerHost
12             
13 
14             #region 远程回调
15             Console.WriteLine( "开始Tcp注册信道" );
16             BinaryServerFormatterSinkProvider formatter =  new  BinaryServerFormatterSinkProvider(); //二进制格式化器
17             formatter.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; //设置过滤类型为Full
18 
19             IDictionary channel =  new  Hashtable();
20             channel[ "name" ] =  "RWCTmyclass" ;
21             channel[ "port" ] = 8003;
22 
23             IChannel tcpChannel =  new  TcpChannel(channel,  null , formatter);
24             ChannelServices.RegisterChannel(tcpChannel,  false ); //注册Tcp类型信道
25             Console.WriteLine( "Tcp信道注册完成————————————————" );
26             Console.WriteLine( "开始 服务器激活类型Singleleton模式的宿主服务器端类型注册" );
27             RemotingConfiguration.RegisterWellKnownServiceType( typeof (MyClass),  "RWCTmyclass" , WellKnownObjectMode.Singleton);
28             Console.WriteLine( "类型注册完成" );
29             #endregion
30 
31 
32             Thread.Sleep( new  TimeSpan(0, 2, 0));
33 
34             Console.WriteLine( "释放Tcp信道" );
35             ChannelServices.UnregisterChannel(tcpChannel);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  1 客户端:
 
  using  System.Runtime.Remoting;
  using  System.Runtime.Remoting.Channels;
  using  System.Runtime.Remoting.Channels.Http;
  using  System.Runtime.Remoting.Channels.Tcp;
  using  System.Runtime.Remoting.Channels.Ipc;
  using  System.Runtime.Remoting.Services;
 
10  using  System.Threading;
11 
12  using  RemoteServer;
13 
14  namespace  RemoteClient
15 
16 
17             #region 远程回调
18             Thread.Sleep( new  TimeSpan(0, 0, 7));
19             IChannel tcp =  new  TcpChannel(0);
20             ChannelServices.RegisterChannel(tcp,  false );
21              string  url =  "tcp://localhost:8003/RWCTmyclass" ;
22             Console.WriteLine( "开始客户端注册类型" );
23             RemotingConfiguration.RegisterWellKnownClientType( typeof (MyClass), url);
24             #endregion
25 
26             Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
27             MyClass myclass =  new  MyClass();
28             myclass.Count();
29             EventMehtodClass methodclass =  new  EventMehtodClass();
30             myclass.NumberChanged += methodclass.OnNumberChanged;
31             Thread.Sleep(100);
32             myclass.OnNumberChanged(100);

图-3

在Singleton激活方式下是可以完成远程回调的,但是用Singlecall模式的话则不行,因为如果是这样的话,之前对远程对象(服务器对象)的操作都没有状态保存,上面说到过,Singlecall模式是一来一回则被释放掉了,本地客户端仅仅是保留了一个代理。可以验证一下:

修改宿主服务端的代码Singleton改为SingleCall

1
1 RemotingConfiguration.RegisterWellKnownServiceType( typeof (MyClass),  "RWCTmyclass" , WellKnownObjectMode.SingleCall);

修改客户端的代码 myclass.Count();又新加一句

1
2
3
4
5
6
7
1             MyClass myclass =  new  MyClass();
2             myclass.Count();
3             myclass.Count();
4             EventMehtodClass methodclass =  new  EventMehtodClass();
5             myclass.NumberChanged += methodclass.OnNumberChanged;
6             Thread.Sleep(100);
7             myclass.OnNumberChanged(100);

修改后的运行结果:
图4

为什么没有像图1中的那样发生回调这里已经不用说明了。

 

 




     本文转自jinyuan0829 51CTO博客,原文链接:http://blog.51cto.com/jinyuan/1422434,如需转载请自行联系原作者







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值