分类目录

链接

2011 年 12 月
 1234
567891011
12131415161718
19202122232425
262728293031  

近期文章

热门标签

新人福利,免费薅羊毛

现在位置:    首页 > .NET > 正文
Remoting系列之远程对象
.NET 暂无评论 阅读(2,445)

前面几篇文章,我们说到Remoting的其它几个方法,今天我们说说Remoting系列中的远程对象,对于 MBR,我们可以指定不同的激活模式。

  • 服务器激活(Server-Activated Objects / SAO):只有在客户端调用代理对象第一个方法时才创建,区分为 Singleton 和 SingleCall 两种模式。Singleton 一如设计模式中的名称,无论有多少客户端都只有一个实例存在;而 SingleCall 则为每次调用创建一个新对象,因此它是无状态的。SingleCall 在方法调用完成后立即失效,不会参与生存期租约系统。
  • 客户端激活(Client-Activated Objects / CAO):在客户端调用 new 或 Activator.CreateInstance 时立即创建。

通常情况下服务器激活模式只能使用默认构造函数,客户端激活模式则没有此限制。当然,可以通过其他方法来绕开这个限制,比如动态发布,我们会在后面的章节解决这个问题。

Remoting 中,我们使用 RemotingConfiguration 类型来完成远程类型的注册。RegisterWellKnownServiceType()、RegisterWellKnownClientType() 用于注册服务器激活对象,通过 WellKnownObjectMode 枚举参数可以指定 Singleton 或 SingleCall 模式。RegisterActivatedServiceType()、RegisterActivatedClientType() 用于注册客户端激活对象。

注册方式演示

1. SAO / Singleton

// Server
RemotingConfiguration.RegisterWellKnownServiceType(typeof(Data), "data", WellKnownObjectMode.Singleton);

...

// Client1
RemotingConfiguration.RegisterWellKnownClientType(typeof(Data), "tcp://localhost:801/data");
Data data = new Data(); // 必须使用默认构造方法。 

...

// Client2
Data data = (Data)Activator.GetObject(typeof(Data), "tcp://localhost:801/data");

2. SAO / SingleCall

// Server
RemotingConfiguration.RegisterWellKnownServiceType(typeof(Data), "data", WellKnownObjectMode.SingleCall);

...

// Client1
RemotingConfiguration.RegisterWellKnownClientType(typeof(Data), "tcp://localhost:801/data");
Data data = new Data(); // 必须使用默认构造方法。

...

// Client2
Data data = (Data)Activator.GetObject(typeof(Data), "tcp://localhost:801/data");

3. CAO

由于 RegisterActivatedServiceType 中不能为远程对象指定 URI,因此我们需要使用 ApplicationName 属性。

// Server
RemotingConfiguration.ApplicationName = "test"; //
RemotingConfiguration.RegisterActivatedServiceType(typeof(Data));

...

// Client1
RemotingConfiguration.RegisterActivatedClientType(typeof(Data), "tcp://localhost:801/test");
Data data = new Data(123); // 可以使用非默认构造方法

...

// Client2
RemotingConfiguration.RegisterActivatedClientType(typeof(Data), "tcp://localhost:801/test");
Data data = (Data)Activator.CreateInstance(typeof(Data), 123);  // 可以使用非默认构造方法

创建时间的区别

我们在远程对象创建和方法调用代码之间进行一些延时来观察创建时间的异同。

1. 服务器激活

  1. using System;
  2. using System.Threading;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Reflection;
  6. using System.Runtime.Serialization;
  7. using System.Runtime.Serialization.Formatters;
  8. using System.Runtime.Serialization.Formatters.Binary;
  9. using System.Runtime.CompilerServices;
  10. using System.Runtime.Remoting;
  11. using System.Runtime.Remoting.Channels;
  12. using System.Runtime.Remoting.Channels.Tcp;
  13. using System.Runtime.Remoting.Messaging;
  14.  
  15. namespace Learn.Library.Remoting
  16. {
  17.     public class RemotingTest2
  18.     {
  19.         /// <summary>
  20.         /// 远程类型
  21.         /// </summary>
  22.         public class Data : MarshalByRefObject
  23.         {
  24.             public Data()
  25.             {
  26.                 Console.WriteLine(DateTime.Now);
  27.             }
  28.  
  29.             public void Test()
  30.             {
  31.                 Console.WriteLine(DateTime.Now);
  32.             }
  33.         }
  34.  
  35.         /// <summary>
  36.         /// 服务器端代码
  37.         /// </summary>
  38.         static void Server()
  39.         {
  40.             // 创建新的应用程序域,以便模拟分布结构。
  41.             AppDomain server = AppDomain.CreateDomain("server");
  42.             server.DoCallBack(delegate
  43.             {
  44.                 // 创建并注册信道
  45.                 TcpServerChannel channel = new TcpServerChannel(801);
  46.                 ChannelServices.RegisterChannel(channel, false);
  47.  
  48.                 // 注册远程类型
  49.                 RemotingConfiguration.RegisterWellKnownServiceType(typeof(Data), "data",
  50.                     WellKnownObjectMode.SingleCall);
  51.             });
  52.         }
  53.  
  54.         /// <summary>
  55.         /// 客户端代码
  56.         /// </summary>
  57.         static void Client()
  58.         {
  59.             // 创建并注册信道
  60.             TcpClientChannel channel = new TcpClientChannel();
  61.             ChannelServices.RegisterChannel(channel, false);
  62.  
  63.             // 创建远程对象并调用其方法
  64.             Data data = (Data)Activator.GetObject(typeof(Data), "tcp://localhost:801/data");
  65.             Thread.Sleep(3000);
  66.             data.Test();
  67.         }
  68.  
  69.         static void Main()
  70.         {
  71.             Server();
  72.             Client();
  73.         }
  74.     }
  75. }

输出:
2007-2-23 14:22:06
2007-2-23 14:22:06

输出结果表明,对象在方法调用时才被创建。

2. 客户端激活

  1. using System;
  2. using System.Threading;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Reflection;
  6. using System.Runtime.Serialization;
  7. using System.Runtime.Serialization.Formatters;
  8. using System.Runtime.Serialization.Formatters.Binary;
  9. using System.Runtime.CompilerServices;
  10. using System.Runtime.Remoting;
  11. using System.Runtime.Remoting.Channels;
  12. using System.Runtime.Remoting.Channels.Tcp;
  13. using System.Runtime.Remoting.Messaging;
  14.  
  15. namespace Learn.Library.Remoting
  16. {
  17.     public class RemotingTest2
  18.     {
  19.         /// <summary>
  20.         /// 远程类型
  21.         /// </summary>
  22.         public class Data : MarshalByRefObject
  23.         {
  24.             public Data()
  25.             {
  26.                 Console.WriteLine(DateTime.Now);
  27.             }
  28.  
  29.             public void Test()
  30.             {
  31.                 Console.WriteLine(DateTime.Now);
  32.             }
  33.         }
  34.  
  35.         /// <summary>
  36.         /// 服务器端代码
  37.         /// </summary>
  38.         static void Server()
  39.         {
  40.             // 创建新的应用程序域,以便模拟分布结构。
  41.             AppDomain server = AppDomain.CreateDomain("server");
  42.             server.DoCallBack(delegate
  43.             {
  44.                 // 创建并注册信道
  45.                 TcpServerChannel channel = new TcpServerChannel(801);
  46.                 ChannelServices.RegisterChannel(channel, false);
  47.  
  48.                 // 注册远程类型
  49.                 RemotingConfiguration.ApplicationName = "test";
  50.                 RemotingConfiguration.RegisterActivatedServiceType(typeof(Data));
  51.             });
  52.         }
  53.  
  54.         /// <summary>
  55.         /// 客户端代码
  56.         /// </summary>
  57.         static void Client()
  58.         {
  59.             // 创建并注册信道
  60.             TcpClientChannel channel = new TcpClientChannel();
  61.             ChannelServices.RegisterChannel(channel, false);
  62.  
  63.             // 创建远程对象并调用其方法
  64.             RemotingConfiguration.RegisterActivatedClientType(typeof(Data), "tcp://localhost:801/test");
  65.             Data data = new Data();
  66.             Thread.Sleep(3000);
  67.             data.Test();
  68.         }
  69.  
  70.         static void Main()
  71.         {
  72.             Server();
  73.             Client();
  74.         }
  75.     }
  76. }

输出:
2007-2-23 14:25:07
2007-2-23 14:25:10

输出结果证实远程对象在执行 new 语句时被创建。

Singleton 和 SingleCall 的区别

Singleton

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Reflection;
  5. using System.Runtime.Serialization;
  6. using System.Runtime.Serialization.Formatters;
  7. using System.Runtime.Serialization.Formatters.Binary;
  8. using System.Runtime.CompilerServices;
  9. using System.Runtime.Remoting;
  10. using System.Runtime.Remoting.Channels;
  11. using System.Runtime.Remoting.Channels.Tcp;
  12. using System.Runtime.Remoting.Messaging;
  13.  
  14. namespace Learn.Library.Remoting
  15. {
  16.     public class RemotingTest2
  17.     {
  18.         /// <summary>
  19.         /// 远程类型
  20.         /// </summary>
  21.         public class Data : MarshalByRefObject
  22.         {
  23.             private Guid id = Guid.NewGuid();
  24.  
  25.             public void Test()
  26.             {
  27.                 Console.WriteLine(id.ToString());
  28.             }
  29.         }
  30.  
  31.         /// <summary>
  32.         /// 服务器端代码
  33.         /// </summary>
  34.         static void Server()
  35.         {
  36.             // 创建新的应用程序域,以便模拟分布结构。
  37.             AppDomain server = AppDomain.CreateDomain("server");
  38.             server.DoCallBack(delegate
  39.             {
  40.                 // 创建并注册信道
  41.                 TcpServerChannel channel = new TcpServerChannel(801);
  42.                 ChannelServices.RegisterChannel(channel, false);
  43.  
  44.                 // 注册远程类型
  45.                 RemotingConfiguration.RegisterWellKnownServiceType(typeof(Data), "data",
  46.                     WellKnownObjectMode.Singleton);
  47.             });
  48.         }
  49.  
  50.         /// <summary>
  51.         /// 客户端代码
  52.         /// </summary>
  53.         static void Client()
  54.         {
  55.             // 创建并注册信道
  56.             TcpClientChannel channel = new TcpClientChannel();
  57.             ChannelServices.RegisterChannel(channel, false);
  58.  
  59.             // 注册远程对象
  60.             RemotingConfiguration.RegisterWellKnownClientType(typeof(Data), "tcp://localhost:801/data");
  61.  
  62.             // 创建远程对象并调用其方法
  63.             Data data1 = new Data();
  64.             Data data2 = new Data();
  65.  
  66.             data1.Test();
  67.             data2.Test();
  68.         }
  69.  
  70.         static void Main()
  71.         {
  72.             Server();
  73.             Client();
  74.         }
  75.     }
  76. }

输出:
94cc586b-a24f-4633-9c88-c98a93246453
94cc586b-a24f-4633-9c88-c98a93246453

两个不同的代理对象引用了同一个远程对象,符合 Singleton 的定义。

SingleCall

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Reflection;
  5. using System.Runtime.Serialization;
  6. using System.Runtime.Serialization.Formatters;
  7. using System.Runtime.Serialization.Formatters.Binary;
  8. using System.Runtime.CompilerServices;
  9. using System.Runtime.Remoting;
  10. using System.Runtime.Remoting.Channels;
  11. using System.Runtime.Remoting.Channels.Tcp;
  12. using System.Runtime.Remoting.Messaging;
  13.  
  14. namespace Learn.Library.Remoting
  15. {
  16.     public class RemotingTest2
  17.     {
  18.         /// <summary>
  19.         /// 远程类型
  20.         /// </summary>
  21.         public class Data : MarshalByRefObject
  22.         {
  23.             private Guid id = Guid.NewGuid();
  24.  
  25.             public void Test()
  26.             {
  27.                 Console.WriteLine(id.ToString());
  28.             }
  29.         }
  30.  
  31.         /// <summary>
  32.         /// 服务器端代码
  33.         /// </summary>
  34.         static void Server()
  35.         {
  36.             // 创建新的应用程序域,以便模拟分布结构。
  37.             AppDomain server = AppDomain.CreateDomain("server");
  38.             server.DoCallBack(delegate
  39.             {
  40.                 // 创建并注册信道
  41.                 TcpServerChannel channel = new TcpServerChannel(801);
  42.                 ChannelServices.RegisterChannel(channel, false);
  43.  
  44.                 // 注册远程类型
  45.                 RemotingConfiguration.RegisterWellKnownServiceType(typeof(Data), "data",
  46.                     WellKnownObjectMode.SingleCall);
  47.             });
  48.         }
  49.  
  50.         /// <summary>
  51.         /// 客户端代码
  52.         /// </summary>
  53.         static void Client()
  54.         {
  55.             // 创建并注册信道
  56.             TcpClientChannel channel = new TcpClientChannel();
  57.             ChannelServices.RegisterChannel(channel, false);
  58.  
  59.             // 创建远程对象并调用其方法
  60.             Data data = (Data)Activator.GetObject(typeof(Data), "tcp://localhost:801/data");
  61.  
  62.             data.Test();
  63.             data.Test();
  64.         }
  65.  
  66.         static void Main()
  67.         {
  68.             Server();
  69.             Client();
  70.         }
  71.     }
  72. }

输出:
6141870b-43db-4d2f-a991-73ae4097ffd3
8e28bf26-5aab-4975-a36a-da61a4bcb93e

 

 

即便是同一个代理对象,也会为每次方法调用创建一个新的远程对象。

 
文章就到这里了,有什么问题留言^_^

============ 欢迎各位老板打赏~ ===========

本文版权归Bruce's Blog所有,转载引用请完整注明以下信息:
本文作者:Bruce
本文地址:Remoting系列之远程对象 | Bruce's Blog

发表评论

留言无头像?