惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

MyScale Blog
MyScale Blog
F
Fortinet All Blogs
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
D
Docker
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
爱范儿
爱范儿
V
Visual Studio Blog
Last Week in AI
Last Week in AI
WordPress大学
WordPress大学
aimingoo的专栏
aimingoo的专栏
小众软件
小众软件
L
LangChain Blog
Vercel News
Vercel News
阮一峰的网络日志
阮一峰的网络日志
IT之家
IT之家
P
Proofpoint News Feed
博客园_首页
D
DataBreaches.Net
T
The Blog of Author Tim Ferriss
The GitHub Blog
The GitHub Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
C
Check Point Blog
Engineering at Meta
Engineering at Meta
Microsoft Azure Blog
Microsoft Azure Blog

博客园 - 编程山人

品牌大全 控制只生成一个子窗体(简单) C#类中的get 和set 函数的具体用法 What's TM? 在C#中利用SharpZipLib进行文件的压缩和解压缩 在C#中运用SQLDMO备份和恢复Microsoft SQL Server数据库 WinForm实现SQLServer存储图片 通过C#调用CHM帮助文件 [Remoting专题系列] 一:.NET Remoting [Remoting专题系列] 二:远程对象 [Remoting专题系列] 四:生存期租约 [Remoting专题系列] 五:信道 [Remoting专题系列] 六:异步调用 [Remoting专题系列] 七:调用上下文 [Remoting专题系列] 八:元数据 [Remoting专题系列] 九:动态发布 [Remoting专题系列] 十:追踪服务 [Remoting专题系列] 十一:事件 [Remoting专题系列] 十二:配置文件
[Remoting专题系列] 三:激活模式
编程山人 · 2007-06-05 · via 博客园 - 编程山人

对于 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. 服务器激活
using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Messaging;

namespace Learn.Library.Remoting
{
  
public class RemotingTest2
  
{
    
/// <summary>
    
/// 远程类型
    
/// </summary>

    public class Data : MarshalByRefObject
    
{
      
public Data()
      
{
        Console.WriteLine(DateTime.Now);
      }


      
public void Test()
      
{
        Console.WriteLine(DateTime.Now);
      }

    }


    
/// <summary>
    
/// 服务器端代码
    
/// </summary>

    static void Server()
    
{
      
// 创建新的应用程序域,以便模拟分布结构。
      AppDomain server = AppDomain.CreateDomain("server");
      server.DoCallBack(
delegate
      
{
        
// 创建并注册信道
        TcpServerChannel channel = new TcpServerChannel(801);
        ChannelServices.RegisterChannel(channel, 
false);

        
// 注册远程类型
        RemotingConfiguration.RegisterWellKnownServiceType(typeof(Data), "data",
          WellKnownObjectMode.SingleCall);
      }
);
    }


    
/// <summary>
    
/// 客户端代码
    
/// </summary>

    static void Client()
    
{
      
// 创建并注册信道
      TcpClientChannel channel = new TcpClientChannel();
      ChannelServices.RegisterChannel(channel, 
false);

      
// 创建远程对象并调用其方法
      Data data = (Data)Activator.GetObject(typeof(Data), "tcp://localhost:801/data");
      Thread.Sleep(
3000);
      data.Test();
    }


    
static void Main()
    
{
      Server();
      Client();
    }

  }

}


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

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

2. 客户端激活
using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Messaging;

namespace Learn.Library.Remoting
{
  
public class RemotingTest2
  
{
    
/// <summary>
    
/// 远程类型
    
/// </summary>

    public class Data : MarshalByRefObject
    
{
      
public Data()
      
{
        Console.WriteLine(DateTime.Now);
      }


      
public void Test()
      
{
        Console.WriteLine(DateTime.Now);
      }

    }


    
/// <summary>
    
/// 服务器端代码
    
/// </summary>

    static void Server()
    
{
      
// 创建新的应用程序域,以便模拟分布结构。
      AppDomain server = AppDomain.CreateDomain("server");
      server.DoCallBack(
delegate
      
{
        
// 创建并注册信道
        TcpServerChannel channel = new TcpServerChannel(801);
        ChannelServices.RegisterChannel(channel, 
false);

        
// 注册远程类型
        RemotingConfiguration.ApplicationName = "test";
        RemotingConfiguration.RegisterActivatedServiceType(
typeof(Data));
      }
);
    }


    
/// <summary>
    
/// 客户端代码
    
/// </summary>

    static void Client()
    
{
      
// 创建并注册信道
      TcpClientChannel channel = new TcpClientChannel();
      ChannelServices.RegisterChannel(channel, 
false);

      
// 创建远程对象并调用其方法
      RemotingConfiguration.RegisterActivatedClientType(typeof(Data), "tcp://localhost:801/test");
      Data data 
= new Data();
      Thread.Sleep(
3000);
      data.Test();
    }


    
static void Main()
    
{
      Server();
      Client();
    }

  }

}


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

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

Singleton 和 SingleCall 的区别

Singleton
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Messaging;

namespace Learn.Library.Remoting
{
  
public class RemotingTest2
  
{
    
/// <summary>
    
/// 远程类型
    
/// </summary>

    public class Data : MarshalByRefObject
    
{
      
private Guid id = Guid.NewGuid();

      
public void Test()
      
{
        Console.WriteLine(id.ToString());
      }

    }


    
/// <summary>
    
/// 服务器端代码
    
/// </summary>

    static void Server()
    
{
      
// 创建新的应用程序域,以便模拟分布结构。
      AppDomain server = AppDomain.CreateDomain("server");
      server.DoCallBack(
delegate
      
{
        
// 创建并注册信道
        TcpServerChannel channel = new TcpServerChannel(801);
        ChannelServices.RegisterChannel(channel, 
false);

        
// 注册远程类型
        RemotingConfiguration.RegisterWellKnownServiceType(typeof(Data), "data",
          WellKnownObjectMode.Singleton);
      }
);
    }


    
/// <summary>
    
/// 客户端代码
    
/// </summary>

    static void Client()
    
{
      
// 创建并注册信道
      TcpClientChannel channel = new TcpClientChannel();
      ChannelServices.RegisterChannel(channel, 
false);

      
// 注册远程对象
      RemotingConfiguration.RegisterWellKnownClientType(typeof(Data), "tcp://localhost:801/data");

      
// 创建远程对象并调用其方法
      Data data1 = new Data();
      Data data2 
= new Data();

      data1.Test();
      data2.Test();
    }


    
static void Main()
    
{
      Server();
      Client();
    }

  }

}


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

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

SingleCall
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Messaging;

namespace Learn.Library.Remoting
{
  
public class RemotingTest2
  
{
    
/// <summary>
    
/// 远程类型
    
/// </summary>

    public class Data : MarshalByRefObject
    
{
      
private Guid id = Guid.NewGuid();

      
public void Test()
      
{
        Console.WriteLine(id.ToString());
      }

    }


    
/// <summary>
    
/// 服务器端代码
    
/// </summary>

    static void Server()
    
{
      
// 创建新的应用程序域,以便模拟分布结构。
      AppDomain server = AppDomain.CreateDomain("server");
      server.DoCallBack(
delegate
      
{
        
// 创建并注册信道
        TcpServerChannel channel = new TcpServerChannel(801);
        ChannelServices.RegisterChannel(channel, 
false);

        
// 注册远程类型
        RemotingConfiguration.RegisterWellKnownServiceType(typeof(Data), "data",
          WellKnownObjectMode.SingleCall);
      }
);
    }


    
/// <summary>
    
/// 客户端代码
    
/// </summary>

    static void Client()
    
{
      
// 创建并注册信道
      TcpClientChannel channel = new TcpClientChannel();
      ChannelServices.RegisterChannel(channel, 
false);

      
// 创建远程对象并调用其方法
      Data data = (Data)Activator.GetObject(typeof(Data), "tcp://localhost:801/data");

      data.Test();
      data.Test();
    }


    
static void Main()
    
{
      Server();
      Client();
    }

  }

}


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

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