很是郁闷,本来写好了,修改提交了几次又没了一大半,只好简单地重新写一点了。
我说话比较喜欢简洁,直接看代码吧(例子根据《Advanced .NET Remoting》一书而来):
Server端:
![](/Images/OutliningIndicators/ContractedBlock.gif)
Using directives#region Using directives
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Lifetime;
using System.Runtime.Remoting.Services;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
#endregion
namespace Server
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
class Server
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
static void Main(string[] args)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
RemotingConfiguration.ApplicationName = "SomeServer";
RemotingConfiguration.Configure("server.exe.config");
Console.WriteLine("Server started.");
Console.ReadLine();
}
}
public class SomeCAO : MarshalByRefObject
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
public void doSomething()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine("SomeCAO.doSomething() is called.");
}
}
}
因为Sponsor是在Client端,所以采用CAO远程对象,SAO对象的生存期是在Server端管理的。
代码很简单,为了方便测试,用配置文件来实现:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="http" port="5555" >
<serverProviders>
<formatter ref="soap" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
<lifetime leaseTime="1S" renewOnCallTime="1S" leaseManagerPollTime = "100MS" />
<service>
<activated type="Server.SomeCAO, Server" />
</service>
</application>
</system.runtime.remoting>
</configuration>
其中
<serverProviders>
<formatter ref="soap" typeFilterLevel="Full"/>
</serverProviders>
这一段,由于在.NET Framework1.1及之后的版本做了安全限制,所以必须要有,否则在客户端注册Sponsor的时候会有异常。
服务端到此为止,然后是客户端,代码如下:
using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Lifetime;
using System.Threading;
using Server; // from generated_meta.dll
namespace Client
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
public class MySponsor : MarshalByRefObject, ISponsor
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
public bool doRenewal = true;
public TimeSpan Renewal(System.Runtime.Remoting.Lifetime.ILease lease)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine("{0} SPONSOR: Renewal() called", DateTime.Now);
if (doRenewal)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine("{0} SPONSOR: Will renew (10 secs)", DateTime.Now);
return TimeSpan.FromSeconds(10);
}
else
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine("{0} SPONSOR: Won't renew further", DateTime.Now);
return TimeSpan.Zero;
}
}
}
class Client
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
static void Main(string[] args)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
String filename = "client.exe.config";
RemotingConfiguration.Configure(filename);
SomeCAO cao = new SomeCAO();
ILease le = (ILease)cao.GetLifetimeService();
MySponsor sponsor = new MySponsor();
le.Register(sponsor);
try
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine("{0} CLIENT: Calling doSomething()", DateTime.Now);
cao.doSomething();
}
catch (Exception e)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine(" -> EX: Timeout in first call\n{0}", e.Message);
}
Console.WriteLine("{0} CLIENT: Sleeping for 5 seconds", DateTime.Now);
Thread.Sleep(5000);
try
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine("{0} CLIENT: Calling doSomething()", DateTime.Now);
cao.doSomething();
}
catch (Exception e)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine(" -> EX: Timeout in second call\n{0}", e.Message);
}
Console.WriteLine("{0} CLIENT: Telling sponsor to stop", DateTime.Now);
sponsor.doRenewal = false;
Console.WriteLine("{0} CLIENT: Sleeping for 10 seconds", DateTime.Now);
Thread.Sleep(10000);
try
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine("{0} CLIENT: Calling doSomething()", DateTime.Now);
cao.doSomething();
}
catch (Exception e)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine(" -> EX: Timeout in third call\n{0}", e.Message);
}
Console.WriteLine("Finished
press <return> to exit");
Console.ReadLine();
}
}
}
在激活了远程对象后,使用GetLifetimeService方法获得跟该对象关联的租约对象,然后在该租约上注册一个新创建的我自定义的主办方对象。
在第一次调用远程对象的方法的时候,由于远程对象生存期还没有超时,所以一切正常。第二此调用之前睡眠了5秒。在这期间,远程对象的生存期超时了。所以服务端的租约管理器会询问该对象的所有主办方,看是否有主办方愿意续订租约。这时,客户端的主办方的Renewal方法会被调用,将远程对象生存期加上10秒。这样在第二次调用远程对象方法时也是正常的(在客户端可以看到Renewal方法被调用了)。然后我们把主办方的一个标志置为false,接着睡眠10秒。在这期间,远程对象生存期又会超时,租约管理器同样调用了客户端的主办方的Renewal方法,但是这一次并没有增加远程对象生存期。所以服务端的垃圾回收器会销毁远程对象的租约和对象本身。在接下来的第三次调用远程对象方法时就会产生异常并被捕获了。
客户端的配置文件如下:
<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="http" port="0" >
<serverProviders>
<formatter ref="soap" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
<client url="http://localhost:5555/SomeServer" >
<activated type="Server.SomeCAO, generated_meta" />
</client>
</application>
</system.runtime.remoting>
</configuration>
最重要的还是
<serverProviders>
<formatter ref="soap" typeFilterLevel="Full"/>
</serverProviders>
为什么在客户端也需要呢?因为在服务端的租约管理器调用客户端主办方的Renewal方法的过程中,客户端充当了Server的角色,而服务端则扮演了Client的角色,因此在客户端也需要对安全限制做修改。
另外,在编译好服务端项目后,使用Soapsuds工具产生共享程序集:
soapsuds -ia:server -nowp -oa:generated_meta.dll
在客户端项目添加对这个generated_meta.dll的引用,就可以编译成功了。
最后先后运行server和client。结果就是下面这样了:
服务端:
Server started.
SomeCAO.doSomething() is called.
SomeCAO.doSomething() is called.
客户端:
2005-2-23 13:53:08 CLIENT: Calling doSomething()
2005-2-23 13:53:08 CLIENT: Sleeping for 5 seconds
2005-2-23 13:53:10 SPONSOR: Renewal() called
2005-2-23 13:53:10 SPONSOR: Will renew (10 secs)
2005-2-23 13:53:13 CLIENT: Calling doSomething()
2005-2-23 13:53:14 CLIENT: Telling sponsor to stop
2005-2-23 13:53:14 CLIENT: Sleeping for 10 seconds
2005-2-23 13:53:20 SPONSOR: Renewal() called
2005-2-23 13:53:20 SPONSOR: Won't renew further
2005-2-23 13:53:24 CLIENT: Calling doSomething()
-> EX: Timeout in third call
Requested Service not found
Finished ... press <return> to exit