Manage the lifetime of remote objects in depth
在《灵活管理Remote Objects生存期(lifetime)》一文中,提及了Remote Objects生存期管理的一些基本方面,已经可以满足一般基于.Net Remoting的应用。如果你觉得那些关于Remote Objects的生存期管理机制还不满足需求,则可以考虑实现Client端或Server端的Sponser对象。
这里将深入讨论Remote Objects生存期管理的Sponsor机制,Sponsorship is confusing, but also powful。(MSDN译:Sponsor – 主办方, Lease - 生存期租约,LeaseManager -租约管理器)
当Remote Object创建时,Sponsor向Remote Object提出注册。当Remote Object的生存期TTL要结束时,LeaseManager负责与注册的Sponsor联系。如果Sponsor返回一个时间段TimeSpan,通知Remote Object的生存期延长指定时间段;如果Sponsor返回TimeSpan.Zero,则Remote Object结束其生存状态。
Sponsor对象本身是一个MarshalByRefObject对象,并且实现ISponsor接口。另外,Sponsor对象可以存放在Remote Object所在的Server端、其他的Server端、或者是Client端application,但是必须满足.Net Remoting Framework可以访问到Sponsor对象。(注意:如果Sponsor存放在Client端,并且Client在firewall后面,Server端的LeaseManager就无法访问到Sponsor了。)
一个典型的Sponsor对象如下:
public class MySponsor: MarshalByRefObject, ISponsor
{
private bool NeedsRenewal()
{
// check some internal conditions
return true;
}
public TimeSpan Renewal(System.Runtime.Remoting.Lifetime.ILease lease)
{
if (NeedsRenewal())
{
return TimeSpan.FromMinutes(5);
}
else
{
return TimeSpan.Zero;
}
}
}
一般而言,对于CAO(客户端激活对象)对象,Sponsor对象位于Client端。对于SAO(服务端激活对象)则相反。下面分别了解两种情况的Sponsor对象:
1.Client端Sponsor
为了让Remote Objects能够与Client端的Sponsor打交道,需要在Client配置文件中Channel设置port属性。如果没有这个属性,Channel就无法接受来自Server的回调。
<channel ref=”http” port=”0”>
Port=”0”表示允许.Net Remoting Framework选择Client端任一空闲的port。
另外,我们知道在调用CAO远程对象时,还需要为配置文件的client项指定url属性。
注册Sponsor对象,避免Remote Objects过早的释放(Client端application部分示例代码):
string filename = "client.exe.config";
RemotingConfiguration.Configure(filename);
// 实例化CAO对象
SomeCAO cao = new SomeCAO();
// Get an object’s LifetimeService, which will be an ILease object.
ILease le = (ILease) cao.GetLifetimeService();
MySponsor sponsor = new MySponsor();
// Register the sponsor with the server object’s lease
le.Register(sponsor);
…调用Remote method或处理其他事情
// Unresister the sponsor with the server objects
le.Unregister(sponsor);
当application准备让server释放CAO对象实例时,application通过告诉sponsor对象停止更新CAO对象实例的TTL。通常情况下,application通过调用Lease.Unregister()方法来取消sponsor对象的注册,这样CAO对象实例就不会与sponsor联系了。
注意:当你决定使用client端的sponsor时,需要确保server可以访问到client,这样client就不能在firewall或proxy后面。
2.Server端Sponsor
Server端的Sponsor对象一般用来管理SAO对象的生存期,在实现方式上基本与Client端Sponsor对象一致。
但是,需要注意的是Remote sponsor对象也是MarshalByRefObject对象,因此也和Remote Objects一样,需要管理其生存期。一般情况下,我们需要Server端sponsor对象与Client端application保持相同的生存期,当Client端application关闭时,要求尽快释放Server端sponsor对象。
Ingo Rammer《Advanced .Net Remoting》中提出了一种方案来实现Server端sponsor对象。
(1) 通过Client端后台线程EnsureKeepAlive对象不断调用sponsor.KeepAlive()方法,确保sponsor对象存活。
(2) 为了防止Client端application意外关闭或出现网络连接故障,无法正确调用Unregister()方法来取消注册,造成Remote Objects和sponsor对象一直存活。为了解决这一潜在问题,在sponsor.KeepAlive()方法中记录更新lastKeepAlive的时间,并在sponsor.Renewal()方法判断renew请求是否在指定的时间间隔内,如果是,则返回指定的TTL时间段,反之,则返回TimeSpan.Zero。注意Server和Client端主要类如上图所示,Source Code请参考《Advance .Net Remoting》Chapter 6(Remote Object和sponsor可以为CAO或SAO对象)。
Reference:
1. Ingo Rammer, Advanced .Net Remoting.
2. Rickie, 《灵活管理Remote Objects生存期(lifetime)》