当前位置: 首页 > 编程日记 > 正文

Microsoft .Net Remoting系列专题之二:Marshal、Disconnect与生命周期以及跟踪服务

Microsoft .Net Remoting系列专题之二 

一、远程对象的激活

在Remoting中有三种激活方式,一般的实现是通过RemotingServices类的静态方法来完成。工作过程事实上是将该远程对象注册到通道中。由于Remoting没有提供与之对应的Unregister方法来注销远程对象,所以如果需要注册/注销指定对象,微软推荐使用Marshal(一般译为编组)和Disconnect配对使用。在《Net Remoting基础篇》中我已经谈到:Marshal()方法是将MarshalByRefObject类对象转化为ObjRef类对象,这个对象是存储生成代理以与远程对象通讯所需的所有相关信息。这样就可以将该实例序列化以便在应用程序域之间以及通过网络进行传输,客户端就可以调用了。而Disconnect()方法则将具体的实例对象从通道中断开。

根据上述说明,Marshal()方法对远程对象以引用方式进行编组(Marshal-by-Reference,MBR),并将对象的代理信息放到通道中。客户端可以通过Activator.GetObject()来获取。如果用户要注销该对象,则通过调用Disconnect()方法。那么这种方式对于编组的远程对象是否存在生命周期的管理呢?这就是本文所要描述的问题。

二、生命周期

在CLR中,框架提供了GC(垃圾回收器)来管理内存中对象的生命周期。同样的,.Net Remoting使用了一种分布式垃圾回收,基于租用的形式来管理远程对象的生命周期。

早期的DCOM对于对象生命周期的管理是通过ping和引用计数来确定对象何时应当作为垃圾回收。然而ping引起的网络流量对分布式应用程序的性能是一种痛苦的负担,它大大地影响了分布式处理的整体性能。.Net Remoting在每个应用程序域中都引入一个租用管理器,为每个服务器端的SingleTon,或每个客户端激活的远程对象保存着对租用对象的引用。(说明:对于服务器端激活的SingleCall方式,由于它是无状态的,对于每个激活的远程对象,都由CLR的GC来自动回收,因此对于SingleCall模式激活的远程对象,不存在生命周期的管理。)

1、租用

租用是个封装了TimeSpan值的对象,用以管理远程对象的生存期。在.Net Remoting中提供了定义租用功能的ILease接口。当Remoting通过SingleTon模式或客户端激活模式来激活远程对象时,租用对象调用从System.MarshalByRefObject继承的InitializeLifetimeService方法,向对象请求租用。

ILease接口定义了有关生命周期的属性,均为TimeSpan值。如下:
InitialLeaseTime:初始化有效时间,默认值为300秒,如果为0,表示永不过期;
RenewOnCallTime:调用远程对象一个方法时的租用更新时间,默认值为120秒;
SponsorshipTimeout:超时值,通知Sponsor(发起人)租用过期后,Remoting会等待的时间,默认值为120秒;
CurrentLeaseTime:当前租用时间,首次获得租用时,为InitializeLeaseTime的值。

Remoting的远程对象因为继承了MarshalByRefObject,因此默认继承了InitializeLifetimeService方法,那么租用的相关属性为默认值。如果要改变这些设置,可以在远程对象中重写该方法。例如:
 public override object InitializeLifetimeService()
 {
  ILease lease = (ILease)base.InitializeLifetimeService();
  if (lease.CurrentState == LeaseState.Initial)
  {
   lease.InitialLeaseTime = TimeSpan.FromMinutes(1);
   lease.RenewOnCallTime = TimeSpan.FromSeconds(20);
  }
  return lease;  
 }

也可以忽略该方法,将对象的租用周期改变为无限:
 public override object InitializeLifetimeService()
 {
  return null;
 }

2、租用管理器

如果是前面所说的租用主要是应用在每个具体的远程对象上,那么租用管理器是服务器端专门用来管理远程对象生命周期的管理器,它维持着一个System.Hashtable成员,将租用映射为System.DateTime实例表示每个租用何时应过期。Remoting采用轮询的方式以一定的时间唤醒租用管理器,检查每个租用是否过期。默认为每10秒钟唤醒一次。轮询的间隔可以配置,如将轮询间隔设置为5分钟:LifetimeService.LeaseManagerPollTime = System.TimeSpan.FromMinutes(5);

我们还可以在租用管理器中设置远程对象租用的属性,如改变远程对象的初始有效时间为永久有效:
LifetimeServices.LeaseTime = TimeSpan.Zero;

我们也可以通过配置文件来设置生命周期,如:
<configuration>
 <system.runtime.remoting>
  <application name = "SimpleServer">
   <lifetime leaseTime = "0" sponsorshipTimeOut = "1M" renewOnCallTime = "1M" pollTime = "30S"/>       
  </application>
 </system.runtime.remoting>
</configuration>

注:配置文件中的pollTime即为上面所说的租用管理器的轮询间隔时间LeaseManagerPollTime。

租用管理器对于生命周期的设置是针对服务器上所有的远程对象。当我们通过配置文件或租用管理器设置租用的属性时,所有远程对象的生命周期都遵循该设置,除非我们对于指定的远程对象通过重写InitializeLifetimeService方法,改变了相关配置。也就是说,远程对象的租用配置优先级高于服务器端配置。

3、发起人(Sponsor)

发起人是针对客户端而言的。远程对象就是发起人要租用的对象,发起人可以与服务器端签订租约,约定租用时间。一旦到期后,发起人还可以续租,就像现实生活中租方的契约,房东、租房者之间的关系一样。

在.Net Framework中的System.Runtime.Remoting.Lifetime命名空间中定义了ClientSponsor类,该类继承了System.MarshalByRefObject,并实现了ISponsor接口。ClientSponsor类的属性和方法,可以参考MSDN。

客户端要使用发起人机制,必须创建ClientSponsor类的一个实例。然后调用相关方法如Register()或Renewal()方法来注册远程对象或延长生命周期。如:
RemotingObject obj = new RemotingObject();
ClientSponsor sponsor = new ClientSponsor();
sponsor.RenewalTime = TimeSpan.FromMinutes(2);
sponsor.Register(obj);

续租时间也可以在ClientSponsor的构造函数中直接设置,如:
ClientSponsor sponsor = new ClientSponsor(TimeSpan.FromMinutes(2));
sponsor.Register(obj);

我们也可以自己编写Sponsor来管理发起人机制,这个类必须继承ClientSponsor并实现ISponsor接口。

三、跟踪服务

如前所述,我们要判断通过Marshal编组远程对象是否存在生命周期的管理。在Remoting中,可以通过跟踪服务程序来监视MBR对象的编组进程。

我们可以创建一个简单的跟踪处理程序,该程序实现接口ITrackingHandler。接口ITrackingHandler定义了3个方法,MarshalObject、UnmarshalObject和DisconnectedObject。当远程对象被编组、解组和断开连接时,就会调用相应的方法。下面是该跟踪处理类的代码:public class MyTracking:ITrackingHandler
{
 public MyTracking()
 {
  //
  // TODO: 在此处添加构造函数逻辑
  //
 }

public void MarshaledObject(object obj,ObjRef or)
 {
  Console.WriteLine();
  Console.WriteLine("对象" + obj.Tostring() + " is marshaled at " + DateTime.Now.ToShortTimeString());
 }

public void UnmarshaledObject(object obj,ObjRef or)
 {
  Console.WriteLine();
  Console.WriteLine("对象" + obj.Tostring() + " is unmarshaled at " + DateTime.Now.ToShortTimeString());
 }

public void DisconnectedObject(object obj)
 {
  Console.WriteLine(obj.ToString() + " is disconnected at " + DateTime.Now.ToShortTimeString());
 }
}

然后再服务器端创建该跟踪处理类的实例,并注册跟踪服务:
TrackingServices.RegisterTrackingHandler(new MyTracking());

四、测试

1、建立两个远程对象,并重写InitializeLifetimeService方法:

对象一:AppService1
初始生命周期:1分钟

public class AppService1:MarshalByRefObject
 {
  public void PrintString(string contents)
  {
   Console.WriteLine(contents);   
  }

public override object InitializeLifetimeService()
  {
   ILease lease = (ILease)base.InitializeLifetimeService();
   if (lease.CurrentState == LeaseState.Initial)
   {
    lease.InitialLeaseTime = TimeSpan.FromMinutes(1);
    lease.RenewOnCallTime = TimeSpan.FromSeconds(20);
   }
   return lease;
   
  }
 }

对象二:AppService2
初始生命周期:3分钟

public class AppService2:MarshalByRefObject
 {
  public void PrintString(string contents)
  {
   Console.WriteLine(contents);   
  }

public override object InitializeLifetimeService()
  {
   ILease lease = (ILease)base.InitializeLifetimeService();
   if (lease.CurrentState == LeaseState.Initial)
   {
    lease.InitialLeaseTime = TimeSpan.FromMinutes(3);
    lease.RenewOnCallTime = TimeSpan.FromSeconds(40);
   }
   return lease;
   
  }
 }

为简便起见,两个对象的方法都一样。

2、服务器端

(1) 首先建立如上的监控处理类;

(2) 注册通道:
TcpChannel channel = new TcpChannel(8080);
ChannelServices.RegisterChannel(channel);

(3) 设置租用管理器的初始租用时间为无限:
LifetimeServices.LeaseTime = TimeSpan.Zero;

(4) 创建该跟踪处理类的实例,并注册跟踪服务:
TrackingServices.RegisterTrackingHandler(new MyTracking());

(5) 编组两个远程对象:
ServerAS.AppService1 service1 = new ServerAS1.AppService1();
ObjRef objRef1 = RemotingServices.Marshal((MarshalByRefObject)service1,"AppService1");

ServerAS.AppService2 service2 = new ServerAS1.AppService2();
ObjRef objRef2 = RemotingServices.Marshal((MarshalByRefObject)service2,"AppService2");

(6) 使服务器端保持运行:
Console.WriteLine("Remoting服务启动,按退出..."); 
Console.ReadLine();

3、客户端

通过Activator.GetObject()获得两个远程对象,并调用其方法PrintString。代码略。

4、运行测试

运行服务器端和客户端,由于监控程序将监视远程对象的编组进程,因此在运行开始,就会显示远程对象已经被Marshal:

然后再客户端调用这两个远程对象的PrintString方法,服务器端接受字符串:

一分钟后,远程对象一自动被Disconnect:

此时客户端如要调用远程对象一,会抛出RemotingException异常;

又一分钟后,远程对象二被Disconnect了:

align="center">

用户还可以根据这个代码测试RenewOnCallTime的时间是否正确。也即是说,在对象还未被Disconnect时,调用对象,则从调用对象的这一刻起,其生命周期不再是原来设定的初始有效时间值(InitialLeaseTime),而是租用更新时间值(RenewOnCallTime)。另外,如果这两个远程对象没有重写InitializeLifetimeService方法,则生命周期应为租用管理器所设定的值,为永久有效(设置为0)。那么这两个对象不会被自动Disconnect,除非我们显式指定关闭它的连接。当然,如果我们显式关闭连接,跟踪程序仍然会监视到它的变化,然后显示出来。

五、结论

通过我们的测试,其实结论已经很明显了。通过Marshal编组的对象要受到租用的生命周期所控制。注意对象被Disconnect,并不是指这个对象被GC回收,而是指这个对象保存在通道的相关代理信息被断开了,而对象本身仍然在服务器端存在。

所以我们通过Remoting提供服务,应根据实际情况指定远程对象的生命周期,如果不指定,则为Remoting默认的设定。要让所有的远程对象永久有效,可以通过配置文件或租用管理器将初始有效时间设为0。

转载于:https://www.cnblogs.com/duadu/archive/2006/05/14/6167213.html

相关文章:

luogu P2759 奇怪的函数 二分答案+数论

题目描述 使得 x^x 达到或超过 n 位数字的最小正整数 x 是多少&#xff1f; 输入输出格式 输入格式&#xff1a; 一个正整数 n 输出格式&#xff1a; 使得 x^x 达到 n 位数字的最小正整数 x 输入输出样例 输入样例#1&#xff1a;11 输出样例#1&#xff1a;10 说明 n<2000000…

前端性能毫秒必争方案(一)HTTP请求

在讲http知识之前&#xff0c;有必要提及下网络七层协议OSI(Open System Interconnect)的缩写 犹如水浒里面的七星聚义&#xff0c;没这七星&#xff0c;就没有108将。(已经放置文章最后面) 2. 减少http请求次数原因在于 1、Http连接 RequestHeader 的开销 众所周知&#xff0c…

CodeSmith应用(一)

这个例子仅是一个简单的应用&#xff0c;在我翻译并学习完CodeSmith的英文帮助文档后&#xff0c;对CodeSmith有了一定的了解&#xff0c;开始着手编写一些CodeSmith应用模板&#xff0c;今天按照最早提到的例子自行编写了一个基于表的添加存储过程的生成模板。具体语法前面基础…

01_创建一个新的activityactivity配置清单文件

今天开始学四大组件。今天是学Activity&#xff0c;然后是广播接收者&#xff0c;然后是服务&#xff0c;然后是内容提供者。四大组件&#xff0c;咱们一天一个。Activity就是跟用户交互的界面&#xff0c;大部分的应用都不会只有这么一个界面。创建多个Activity&#xff0c;在…

Java 集合——List集合

Collection接口是集合的老祖宗&#xff0c;定义了接口的基本方法。 List是Collection接口的子接口&#xff0c;也是最常用的接口&#xff0c;此接口对Collection接口进行了大量的扩展&#xff0c;List集合里的元素是可以重复的。 List接口的主要实现类有ArrayList&#xff0c;和…

jQuery中的插件机制

我们在很多地方都用过插件&#xff0c;插件能让我们操作某个东西变得异常方便&#xff0c;jQuery也不例外&#xff0c;为了扩展jQuery库函数&#xff0c;jQuery提供了两种方式&#xff1a; jQuery.extend(object)&#xff1a;扩展jQuery对象本身&#xff0c;主要是用来扩展jQu…

ActiveRecordBase借助NHibernate的条件获取实体类对象

ActiveRecordBase.FindAll() 函数其中有一个这样的版本的参数ActiveRecordBase.FindAll(TargetType AsSystem.Type,Orders() AsNHibernate.Expression.Order,ParamArraycriterias() AsNHibernate.Expression.ICriteriion) 可以方便的使用NHibernate的条件查询&#xff0c;例如…

轻量级持久层V2版本代码与模板

首页列表上好像不能下载&#xff0c;要下载文件请进来下。 上篇帖《轻量级持久层的讨论》中大家踊跃的提出各种意见&#xff0c;让我得到不少灵感&#xff0c;这些新的想法将会应用到下一个版本的开发中&#xff0c;我先得试试可行性如何。这里先给出这一版本的代码和模板&…

最近用到的一些方法技巧

郁闷&#xff0c;msn上不去&#xff0c;没法干活。记上最近项目中用到的一些code snippet1.查询今天的记录select datediff(dd,ConvDateTime,getdate()),* from dbo.rbConversationMaster where datediff(dd,ConvDateTime,getdate())0 DataDiff Returns the number of date and…

MyBatis的使用

要了解MyBatis的使用&#xff0c;首先要了解MyBatis是因何而来的&#xff1f;为了和数据库进行交互&#xff0c;通常的做法是将SQL语句写在Java代码里&#xff0c;然后生成class文件&#xff0c;而我们知道class文件是无法修改的。假如后来我们只想改变一下SQL语句&#xff0c;…

iOS7系统iLEX RAT冬青鼠安装教程:无需刷机还原纯净越狱系统

全网科技 温馨提醒&#xff1a;iLEX RAT和Semi-Restore的作用都是让你的已越狱的设备恢复至越狱的初始状态。可是要注意无论你是用iLexRAT冬青鼠还是Semi-restore。对于还原来说都存在巨大的风险。非必要情况下&#xff0c;还是不要任意使用它们。*iLEX RAT冬青鼠安装教程&…

HDU 4832(DP+计数问题)

HDU 4832 Chess 思路&#xff1a;把行列的情况分别dp求出来&#xff0c;然后枚举行用几行。竖用几行&#xff0c;然后相乘累加起来就是答案 代码&#xff1a; #include <stdio.h> #include <string.h> #include <iostream> using namespace std;typedef long…

社会生活中常用的14条著名法则

一、 马太效应          八、 水桶定律 二、 手表定理          九、 蘑菇管理三、 不值得定律         十、 奥卡姆剃刀定律四、 彼得原理          十一、 二八定律五、 零和游戏原理        十二、 钱的问题六、 华盛顿合作…

Spring框架之(无参、有参)构造方法与setter方法的初始化

我们之前要创建对象时&#xff0c;都需要new一下&#xff0c;但使用了Spring后&#xff0c;就不需要再new了&#xff0c;可以直接使用类名调用了。这是因为Spring 已经为我们自动创建好了Java对象&#xff08;但需要在xml文件里进行一些配置&#xff09;。 举个例子看看吧&…

P1034 矩形覆盖

题目描述 在平面上有 n 个点&#xff08;n < 50&#xff09;&#xff0c;每个点用一对整数坐标表示。例如&#xff1a;当 n&#xff1d;4 时&#xff0c;4个点的坐标分另为&#xff1a;p1&#xff08;1&#xff0c;1&#xff09;&#xff0c;p2&#xff08;2&#xff0c;2&a…

[linux][c语言]用socket实现简单的服务器客户端交互

Socket解释&#xff1a; 网络上的两个程序通过一个双向的通信连接实现数据的交换&#xff0c;这个连接的一端称为一个socket。 Socket的英文原义是“孔”或“插座”。作为BSD UNIX的进程通信机制&#xff0c;取后一种意思。通常也称作"套接字"&#xff0c;用于描述IP…

Spring之注解方式实例化Java类

我们知道一个<bean></bean>就代表一个对象&#xff0c;如果想创建多个对象&#xff0c;就要使用多个<bean></bean>&#xff0c;所以这里有个简便的方法&#xff1a; <context:component-scan base-package"com.jd"></context:comp…

3.Linux Shell流程控制

1.if/else结构 if condition thenstatements elif condition thenstatements elsestatements fi 2.条件 与C语言不同的是&#xff0c;条件(condition)实际上是语句列表&#xff0c;而不是一般的布尔表达式。 按照惯例&#xff0c;函数以及命令的退出状态用0表示成功&#xff0c…

ASP.NET 2.0 中配合 Master Page 使用的优化 CSS 模型

ASP.NET 2.0 中增加了内建的 MasterPage 的支持&#xff0c;这对我们来说是一个很大的便利。然而经过一段时间的使用&#xff0c;我发现 MasterPage 并不是那么完美&#xff1a;嵌套的 MasterPage 不能支持设计时界面&#xff0c;以及下面要提到的Content Page 中增加 CSS 的问…

详细说明Spring--AOP

这篇博客较长&#xff0c;耐心读完或许会有“柳暗花明又一村”的感觉哦&#xff01; 为什么? 我先不说AOP是什么&#xff0c;我先说说为什么要用AOP&#xff0c;依照惯例&#xff0c;我还是先举一个例子&#xff1a; 先把项目结构展现出来&#xff1a; 我们先在com.jd.calcu…

ES6中的Promise详解

Promise 在 JavaScript 中很早就有各种的开源实现&#xff0c;ES6 将其纳入了官方标准&#xff0c;提供了原生 api 支持&#xff0c;使用更加便捷。 定义 Promise 是一个对象&#xff0c;它用来标识 JavaScript 中异步操作的状态&#xff08;pending, resolve, reject&#xff…

Jquery 将表单序列化为Json对象

大家知道Jquery中有serialize方法&#xff0c;可以将表单序列化为一个“&”连接的字符串&#xff0c;但却没有提供序列化为Json的方法。不过&#xff0c;我们可以写一个插件实现。 我在网上看到有人用替换的方法&#xff0c;先用serialize序列化后&#xff0c;将&替换成…

ASP.NET常用函数

Abs(number) 取得数值的绝对值。 Asc(String) 取得字符串表达式的第一个字符ASCII 码。 Atn(number) 取得一个角度的反正切值。 CallByName (object, procname, usecalltype,[args()]) 执行一个对象的方法、设定或传回对象的属性。 CBool(expression) 转换表达式为Boolean …

简单快速修改大量重复代码(Intellij IDEA)

血与泪的教训啊&#xff01;&#xff01;&#xff01;刚开始不知道&#xff0c;一味地疯狂点鼠标和键盘&#xff0c;点到手抽筋才想起来百度一下如何快速修改大量重复代码&#xff0c;呜呜呜~~~ 给大家分享一下吧&#xff0c;可以节约大家大量的时间哦&#xff1a; …

5.3Role和Claims授权「深入浅出ASP.NET Core系列」

5.3Role和Claims授权「深入浅出ASP.NET Core系列」 原文:5.3Role和Claims授权「深入浅出ASP.NET Core系列」希望给你3-5分钟的碎片化学习&#xff0c;可能是坐地铁、等公交&#xff0c;积少成多&#xff0c;水滴石穿&#xff0c;码字辛苦&#xff0c;如果你吃了蛋觉得味道不错&…

電子商務新紀元-WebService With BizSnap

電子商務新紀元-WebService With BizSnap WebService SOAP(Simple Object Access Protocol) Web Services Description Language (WSDL) DELPHI 的SOAP 撰寫WebService Server 程式 撰寫Client 端程式 魔法的秘密 傳送複雜型態資料(Complex Type) 傳送檔案或圖形 處理資料庫 C…

mysql优化1

1.以空间换时间,减少连表查询的次数,适当增加冗余字段 例如: 计算的字段,可以事先统计完,方数据库中,来一个加一个,而不用现场计算 2.字段类型: 整型 > date,time >enum >char >varchar >blob,text 字符串需要考虑字符集和校对集,因此比整型慢 time会考虑时期,用…

用XP做服务器突破10人限制

用XP做服务器突破10人限制用微软提供的小工具 MetaEdit&#xff0c;最新版本是2.2。下载地址:http://download.microsoft.com/download/iis50/Utility/5.0/NT45/EN-US/MtaEdt22.exe安装好以后将树型目录展开至LM \ W3SVC直接在W3SVC文件夹上单击&#xff0c;选择右边列表中Name…

Java反射(详述版)

一、什么是反射&#xff1f; 我们先来看一个例子&#xff1a; package venus; public class Student {public String name;public Student(){System.out.println("无参构造方法");}public void doHomework(){System.out.println(name "正在做作业~~~");…

s9.16作业,员工信息表

转载https://blog.csdn.net/qq_35883464/article/details/83151464 实现员工信息表文件存储格式如下&#xff1a;id&#xff0c;name&#xff0c;age&#xff0c;phone&#xff0c;job1,Alex,22,13651054608,IT2,Egon,23,13304320533,Tearcher3,nezha,25,1333235322,IT 现在需要…