【转】Microsoft .Net Remoting之Marshal、Disconnect与生命周期以及跟踪服务
Marshal、Disconnect与生命周期以及跟踪服务
一、远程对象的激活
在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();
lease.RenewOnCallTime = TimeSpan.FromSeconds();
}
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();
lease.RenewOnCallTime = TimeSpan.FromSeconds();
}
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();
lease.RenewOnCallTime = TimeSpan.FromSeconds();
}
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。
原文地址:http://www.cnblogs.com/wayfarer/archive/2004/08/05/30437.html
【转】Microsoft .Net Remoting之Marshal、Disconnect与生命周期以及跟踪服务的更多相关文章
- Microsoft .Net Remoting系列专题之二
Microsoft .Net Remoting系列专题之二 一.远程对象的激活 在Remoting中有三种激活方式,一般的实现是通过RemotingServices类的静态方法来完成.工作过程事实上是 ...
- Microsoft .Net Remoting系列专题之一:.Net Remoting基础篇
Microsoft .Net Remoting系列专题之一 一.Remoting基础 什么是Remoting,简而言之,我们可以将其看作是一种分布式处理方式.从微软的产品角度来看,可以说Remotin ...
- 【转】Microsoft .Net Remoting 之.Net Remoting基础篇
.Net Remoting基础篇 一.Remoting基础 什么是Remoting,简而言之,我们可以将其看作是一种分布式处理方式.从微软的产品角度来看,可以说Remoting就是DCOM的一种升级, ...
- Microsoft .Net Remoting
什么是Remoting,简而言之,我们可以将其看作是一种分布式处理方式.从微软的产品角度来看,可以说Remoting就是DCOM的一种升级,它改善了很多功能,并极好的融合到.Net平台下.Micros ...
- Microsoft .Net Remoting系列专题之三:Remoting事件处理全接触
前言:在Remoting中处理事件其实并不复杂,但其中有些技巧需要你去挖掘出来.正是这些技巧,仿佛森严的壁垒,让许多人望而生畏,或者是不知所谓,最后放弃了事件在Remoting的使用.关于这个主题,在 ...
- 【转】Microsoft .Net Remoting之Remoting事件处理全接触
Remoting事件处理全接触 前言:在Remoting中处理事件其实并不复杂,但其中有些技巧需要你去挖掘出来.正是这些技巧,仿佛森严的壁垒,让许多人望而生畏,或者是不知所谓,最后放弃了事件在Remo ...
- 【Microsoft Azure 的1024种玩法】六、使用Azure Cloud Shell对Linux VirtualMachines 进行生命周期管理
[文章简介] Azure Cloud Shell 是一个用于管理 Azure 资源的.可通过浏览器访问的交互式经验证 shell. 它使用户能够灵活选择最适合自己工作方式的 shell 体验,本篇文章 ...
- ASP.NET Core 源码阅读笔记(2) ---Microsoft.Extensions.DependencyInjection生命周期管理
在上一篇文章中我们主要分析了ASP.NET Core默认依赖注入容器的存储和解析,这一篇文章主要补充一下上一篇文章忽略的一些细节:有关服务回收的问题,即服务的生命周期问题.有关源码可以去GitHub上 ...
- remoting生命周期
https://www.cnblogs.com/luomingui/archive/2011/07/09/2101779.html
随机推荐
- javascript array操作
首先来看一下怎么判断一个对象是不是数组: 1.Array.isArray(obj) 调用数组的isArray方法 2.obj instanceof Array 判断对象是否是Array的实例 3.Ob ...
- ECSHOP后台权限分配原理分析
1.在权限管理->管理员列表,中添加一名管理员 2.在admin\includes\inc_menu.php $modules['02_cat_and_goods']['01_goods_lis ...
- Hadoop启动过程分析
先把客户端修好,后续慢慢写. 菊子曰:体验离线写博的乐趣
- JSON概述及其在JavaScript与Java中的应用(整理)
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它使得人们很容易的进行阅读和编写.同时也方便了机器进行解析和生成. 官网:http://json.org/ ...
- C++第12周(春)项目2 - "双肩挑"教师
课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759,内有完整教学方案及资源链接 [项目2 - 教师兼干部类](第11章习题9) ...
- JS动态增加删除UL节点LI
JS如何动态增加删除UL节点LI及相关内容. <ul id="ul"> <li id=1>11111111111111111<a href=" ...
- [svc][op]磁盘Inode详解-重要
另一篇白话总结 一.inode是什么 理解inode,要从文件储存说起. 文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector).每个扇区储存512字节(相当于0.5KB ...
- 每日英语:Why 'The Voice' Is China's No. 1 TV Show
U.S. fans of the hit talent show 'The Voice' may take for granted that its judges sit with their bac ...
- cocos2d-x 3.0点击响应
迄今为止,发现cocos2d-x 3.0最让人惊艳的地方就是更改了点击事件机制.(ps:迄今只看了点击事件这块,捂嘴笑~~~) cocos2d-x 2.0 只有CCLayer有点击事件处理,需要注册, ...
- Python+Django+js+echarts引入本地js文件的操作方法
1. 选择正确的echarts.js,开发版选择echarts.baidu.com上的源码版,避免出现问题 2. 在项目主目录中新建static文件夹,里面建立js.css.images文件夹 3. ...