![](http://img.e-com-net.com/image/product/fc15c31aabc44907a96b66d707be8873.jpg)
本次议题 对象生存周期管理
对于服务器对象不保留任何状态的SingleCall对象是不需要有对象租用的。只有需要保留状态的对象,无论是服务器激活的Singleton 还是客户端激活的对象才需要对象租用。
租约
生命周期
发起人(Sponsor)
下面是NET Remoting 为管理远程对象的生存期管理的架构:
![.NET Remoting开发系列:(二) 对象生存周期管理](http://img.e-com-net.com/image/product/bfe2f0bdea0a45a786bff239bbb0660b.png)
ILease 接口定义了很多用于管理对象生存期的属性:
- InitialLeaseTime。确定租用最初的有效期。
- RenewOnCallTime。在每个方法调用后,更新此时间单元的租用。
- SponsorshipTimeout。负责人通知租用过期后,Remoting 要等待的时间。
- CurrentLeaseTime。距租用到期的时间(只读)。
续约的方法有3种:
1)隐式续约:当客户调用远程对象上的方法时,租约的隐式续借会自动进行。
2)显示续约:通过ILease接口的Renew()方法完成。通过调用透明代理对象的GetLifeService()方法,就可以使用ILease接口。
3)发起租约:客户可以创建一个实现ISponsor接口的发起者,并使用ILease接口的Register()方法在租约服务中注册这个发起者。发起者定义租约延长的时间。当租约到期时,发起者就要求延长租约时间。如果长期租约服务器上的远程对象,可以使用这个发起租约机制。
开发Remoting三步走
1、 远程对象:
建立类库项目:General
public
class
ClientActivatedType : MarshalByRefObject
{
public
override
Object InitializeLifetimeService()
{
//
ILease接口定义了有关生命周期的属性,均为TimeSpan值
ILease lease
=
(ILease)
base
.InitializeLifetimeService();
//
该租约状态。
if
(lease.CurrentState
==
LeaseState.Initial)
{
//
初始化有效时间,默认值为300秒,如果为0,表示永不过期;
lease.InitialLeaseTime
=
TimeSpan.FromSeconds(
3
); //这个3改成0,永远不过期。
//
超时值,通知Sponsor(发起人)租用过期后,Remoting会等待的时间,默认值为120秒;
lease.SponsorshipTimeout
=
TimeSpan.FromSeconds(
10
);
//
调用远程对象一个方法时的租用更新时间,默认值为120秒;
lease.RenewOnCallTime
=
TimeSpan.FromSeconds(
2
);
}
return
lease;
}
public
string
RemoteMethod()
{
Console.WriteLine(
"
ClientActivatedType.RemoteMethod called.
"
);
return
"
RemoteMethod called.
"
+
WindowsIdentity.GetCurrent().Name;
}
}
2、服务端建立控制台项目:Server
public
class
Server
{
public
static
void
Main(
string
[] Args)
{
//
读取配置文件
RemotingConfiguration.Configure(
"
server.exe.config
"
);
Console.WriteLine(
"
The server is listening. Press Enter to exit....
"
);
Console.ReadLine();
Console.WriteLine(
"
Recycling memory...
"
);
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
服务器端配置文件 App.config
<
configuration
>
<
system.runtime.remoting
>
<
application
>
<
service
>
<
activated
type
="ClientActivatedType, General"
/>
</
service
>
<
channels
>
<
channel
port
="8080"
ref
="http"
>
<
serverProviders
>
<
formatter
ref
="soap"
typeFilterLevel
="Full"
/>
<
formatter
ref
="binary"
typeFilterLevel
="Full"
/>
</
serverProviders
>
</
channel
>
</
channels
>
</
application
>
</
system.runtime.remoting
>
</
configuration
>
(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、客户端:建立控制台项目:Client
public
class
Client
{
public
static
void
Main(
string
[] Args)
{
RemotingConfiguration.Configure(
"
client.exe.config
"
);
ClientActivatedType CAObject
=
new
ClientActivatedType();
//
租用
ILease serverLease
=
(ILease)RemotingServices.GetLifetimeService(CAObject);
//
发起人(Sponsor) 续租时间
MyClientSponsor sponsor
=
new
MyClientSponsor();
//
Register()或Renewal()方法来注册远程对象或延长生命周期
serverLease.Register(sponsor);
Console.WriteLine(
"
Client-activated object:
"
+
CAObject.RemoteMethod());
Console.WriteLine(
"
Press Enter to end the client application domain.
"
);
Console.ReadLine();
}
}
//
发起人(Sponsor)
public
class
MyClientSponsor : MarshalByRefObject, ISponsor
{
private
DateTime lastRenewal;
public
MyClientSponsor()
{
lastRenewal
=
DateTime.Now;
}
public
TimeSpan Renewal(ILease lease)
{
Console.WriteLine(
"
I've been asked to renew the lease.
"
);
Console.WriteLine(
"
Time since last renewal:
"
+
(DateTime.Now
-
lastRenewal).ToString());
lastRenewal
=
DateTime.Now;
return
TimeSpan.FromSeconds(
20
);
}
}
客户端配置文件 App.config
<
configuration
>
<
system.runtime.remoting
>
<
application
>
<
client
url
="http://localhost:8080"
>
<
activated
type
="ClientActivatedType, General"
/>
</
client
>
<
channels
>
<
channel
ref
="http"
port
="0"
>
<
serverProviders
>
<
formatter
ref
="soap"
typeFilterLevel
="Full"
/>
<
formatter
ref
="binary"
typeFilterLevel
="Full"
/>
</
serverProviders
>
</
channel
>
</
channels
>
</
application
>
</
system.runtime.remoting
>
</ configuration>
通过Marshal编组的对象要受到租用的生命周期所控制。注意对象被Disconnect,并不是指这个对象被GC回收,而是指这个对象保存在通道的相关代理信息被断开了,而对象本身仍然在服务器端存在。
所以我们通过Remoting提供服务,应根据实际情况指定远程对象的生命周期,如果不指定,则为Remoting默认的设定。要让所有的远程对象永久有效,可以通过配置文件或租用管理器将初始有效时间设为0。