Remoting中在客户端使用自定义的Sponsor

很是郁闷,本来写好了,修改提交了几次又没了一大半,只好简单地重新写一点了。

我说话比较喜欢简洁,直接看代码吧(例子根据《Advanced .NET Remoting》一书而来):

Server端:

Using directives

namespace  Server
{
    
class Server
    
{
        
static void Main(string[] args)
        
{
            RemotingConfiguration.ApplicationName 
= "SomeServer";
            RemotingConfiguration.Configure(
"server.exe.config");

            Console.WriteLine(
"Server started.");
            Console.ReadLine();
        }

    }


    
public class SomeCAO : MarshalByRefObject
    
{
        
public void doSomething()
        
{
            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
{
    
public class MySponsor : MarshalByRefObject, ISponsor
    
{

        
public bool doRenewal = true;

        
public TimeSpan Renewal(System.Runtime.Remoting.Lifetime.ILease lease)
        
{
            Console.WriteLine(
"{0} SPONSOR: Renewal() called", DateTime.Now);

            
if (doRenewal)
            
{
                Console.WriteLine(
"{0} SPONSOR: Will renew (10 secs)", DateTime.Now);
                
return TimeSpan.FromSeconds(10);
            }

            
else
            
{
                Console.WriteLine(
"{0} SPONSOR: Won't renew further", DateTime.Now);
                
return TimeSpan.Zero;
            }

        }

    }


    
class Client
    
{
        
static void Main(string[] args)
        
{
            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
            
{
                Console.WriteLine(
"{0} CLIENT: Calling doSomething()", DateTime.Now);
                cao.doSomething();
            }

            
catch (Exception e)
            
{
                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
            
{
                Console.WriteLine(
"{0} CLIENT: Calling doSomething()", DateTime.Now);
                cao.doSomething();
            }

            
catch (Exception e)
            
{
                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
            
{
                Console.WriteLine(
"{0} CLIENT: Calling doSomething()", DateTime.Now);
                cao.doSomething();
            }

            
catch (Exception e)
            
{
                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

你可能感兴趣的:(客户端)