您的位置:首页 > 其它

使用.NET Remoting开发分布式应用——基于租约的生存期

2005-11-28 08:47 453 查看
使用.NET Remoting开发分布式应用——基于租约的生存期

作者:Terrylee

一.概述

知名类型的SingleCall对象可以在客户程序的方法调用之后被垃圾收集器清理掉,因为它没有保持状态,属于无状态的。而客户激活的类型的对象和知名类型的SingleTon对象都属于生存期长的对象,如果在客户程序停止使用远程对象之前,远程对象被禁用了,则客户程序会得到一个RemotingException异常。因为该对象已经和下一个方法调用(从客户程序进行的方法调用)断开了连接,只要客户程序需要该对象,它就必须被激活。

微软的DCOM技术使用了Ping机制,在这种机制下,客户程序有规律的对服务程序发出Ping请求,以通知服务程序自己仍旧活着,并通知服务程序自己需要使用哪个对象。.NET Remoting使用的是基于租约的生存期机制,在租约期内,对象一直存活着,直到租借时间结束,.NET Remoting使用Leasing程序完成了这项工作。

.NET Remoting允许我们通过一些方式来修改对象的租约时间,一种方式是编写程序代码来完成,另外一种方式是使用配置文件(有关配置文件的介绍可以参见《使用.NET Remoting开发分布式应用——配置文件篇》的内容),还有一种方式是通过发起人(Sponsor)来配置租约。先来看一下租约配置选项的默认值:

租约配置

默认值(秒)

LeaseTime

300

RenewOnCallTime

120

SponsorshipTimeout

120

LeaseManagerPollTime

10

使用LeaseTime选项可以定义远程对象的最长租借时间。如果客户程序一段时期内不再需要远程对象了,那么该对象将被禁用。每次客户程序使用远程对象调用方法时,RenewOnCallTime定义的一个值会递增租借时间。SponsorshipTimeout选项定义了在调用结束之前的那段默认时间,而LeaseManagerPollTime定义了发起人必须返回延长的那部分租借时间。

租约可以实现 ILease 接口并存储一个属性集合,用于确定更新的策略和方法。您也可以使用调用来更新租约。每次调用远程对象上的方法时,租约时间都会设置为目前 LeaseTime 最大值加上 RenewOnCallTime。LeaseTime 即将过期时,发起者会被要求更新租约。因为我们有时会遇上网络不稳定,所以可能会找不到租约发起者。为了确保不在服务器上留下无效对象,每个租约都带有一个 SponsorshipTimeout。该值指定了租约终止之前等待租约发起者回复的时间长度。如果 SponsershipTimeout 为零,CurrentLeaseTime 会被用于确定租约的过期时间。如果 CurrentLeaseTime 的值为零,则租约不会过期。配置或 API 可用于替代 InitialLeaseTime、SponsorshipTimeout 和 RenewOnCallTime 的默认值。

租约管理器维护着一个按发起时间从大到小存储的发起者列表(它们实现 ISponsor 接口)。需要调用发起者以更新租约时间时,租约管理器会从列表的顶部开始向一个或多个发起者要求更新租约时间。列表顶部的发起者表示其以前请求的租约更新时间最长。如果发起者没有在 SponsorshipTimeOut 时间段内响应,则它会被从列表中删除。通过调用 GetLifetimeService 并将对象租约作为参数,即可以获得该对象租约。该调用是 RemotingServices 类的一个静态方法。如果对象在应用程序域内部,则该调用的参数是对象的本地引用,且返回的租约也是该租约的本地引用。如果对象是远程的,则代理会作为一个参数传递,且返回给调用方的是租约的透明代理。

二.通过配置文件配置租约

在服务器上的应用程序配置文件中编写生存期的配置。在这种方式下,生存期配置对整个应用程序都有效。在应用程序配置文件的<lifttime>标记中,可以通过修改特性的方式来配置。

示例代码:

1<?xml version="1.0" encoding="utf-8" ?>
2<configuration>
3 <system.runtime.remoting>
4 <application>
5 <service>
6 <wellknown
7 mode="Singleton"
8 type="RemotingSamples.HelloServer, General"
9 objectUri="SayHello" />
10 </service>
11 <channels>
12 <channel port="8086" ref="http"/>
13 </channels>
14
15 <lifetime
16 leaseTime="7M"
17 sponsorshipTimeout="7M"
18 renewOnCallTime="7M"
19 leaseManagerPollTime="7S"
20 />
21 </application>
22 </system.runtime.remoting>
23</configuration>
24

三.编写代码配置租约

如果我们需要一些带有不同的生存期要求的远程对象,那么最好是通过编程的方式来为对象设置生存期。在远程对象中,可以覆盖InitializeLifetimeService()方法。基类MarshalByRefObject中的InitializeLifetimeService()方法会返回一个对Ilease接口(该接口可用于修改默认值)的引用,因为只有在租约没有生效的时候才可能修改默认值,所以,我们需要检查租约的当前状态,并把它和枚举值LeaseState.Initial进行比较。

示例代码:

1 public override Object InitializeLifetimeService()
2using System;
2using System.Runtime.Remoting;
3using System.Runtime.Remoting.Channels;
4using System.Runtime.Remoting.Channels.Tcp;
5using System.Runtime.Remoting.Channels.Http;
6using System.Runtime.Remoting.Activation;
7using System.Runtime.Remoting.Lifetime;
8using System.IO;
9
10namespace RemotingSamples
11


五.总结


通过租约来管理远程对象的生存期可以作为引用计数的一种替代方法,因为当网络连接的性能不可靠时,引用计数会显得复杂和低效。尽管有人会坚持认为远程对象的生存期比所需的时间要长,但与引用计数和连接客户相比,租约降低了网络的繁忙程度,将会成为一种非常受欢迎的解决方案。

附录:一个完整的用程序代码配置租约生存期的例子

Server.cs

1using System;
2using System.Runtime.Remoting;
3using System.Runtime.Remoting.Channels;
4using System.Runtime.Remoting.Channels.Tcp;
5using System.Runtime.Remoting.Channels.Http;
6
7namespace RemotingSamples
8

HelloWord.cs

1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Runtime.Remoting.Lifetime;
5
6namespace RemotingSamples
7
40
41
42
43

Client.cs

1using System;
2using System.Runtime.Remoting;
3using System.Runtime.Remoting.Channels;
4using System.Runtime.Remoting.Channels.Tcp;
5using System.Runtime.Remoting.Channels.Http;
6using System.Runtime.Remoting.Activation;
7using System.Runtime.Remoting.Lifetime;
8using System.IO;
9
10namespace RemotingSamples
11
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: