|   摘要   本文介绍了Net Remoting的几个简单概念,并尝试从最简单的角度帮您理解什么是Remoting。同时,本文包括了一个使用Http 
        Channel调用Remoting服务器的例子,并讨论了不同的Server对象的差别以及对象的生命周期。   通过本篇文章的阅读,用户可以对Remoting的基本概念有了解,并知道几种Server端对象的区别和Server对象生命周期的概念。   Remoting简介   相信很多人都在不同的地方看到Remoting这个名词,其实它的概念很简单。我们通过使用Remoting来进行不同应用程序之间的通信,不管这些程序是在同一台计算机上,还是在局域网内的不同计算机上,甚至在Internet的不同操作系统上(当然相应的操作系统也必须实现了.Net 
        Framework)。Remoting的两大功能在于:   1)不同进程间的通信。2)不同应用域(AppDomain),不同进程的对象之间的通信(可以使用多种通信协议)。
   .NET Remoting框架 Remoting的一个典型示例  为了使用Remoting, .NET提供了一整套框架来使这种分布的调用透明化。它的框架如下图所示:  
          
 图1:.NET Remoting构架图
   通常用到的Remoting的概念有:
 Remoting Channel:这是指客户端和服务器端的通信协议,如我们可以使用TCP, HTTP协议。
 
 Serializer:这是指在传输时采用何种格式来传输数据,如我们可以采用Binary,也可以采用SOAP来传输XML格式的数据.
 
 .NET力图简化这些概念的编程,所以上面所述的协议和格式都可以通过更改配置文件切换。这也是编程人员不用担心的问题。如一段典型的客户端配置文件的内容是:
 
 
          
             
              | <CONFIGURATION> 
 <SYSTEM.RUNTIME.REMOTING>
 
 <APPLICATION>
 
 <CHANNELS>
 
 <CHANNEL ref="http" clientConnectionLimit="200">
 
 <CLIENTPROVIDERS>
 
 <FORMATTER ref="binary">
 
 </CLIENTPROVIDERS>
 
 </CHANNEL>
 
 </CHANNELS>
 
 </APPLICATION>
 
 </SYSTEM.RUNTIME.REMOTING>
 
 </CONFIGURATION>
 | 
 让我们首先来看一个典型的实例。我们会有一个服务器程序Server.exe和一个客户端程序CAOClient.exe。客户端程序会通过http 
      channel调用服务器端RemoteType.dll的对象和方法。我们会来检查在几种不同的Server对象下,这些调用会有什么样不同的结果。
   服务器端代码  
 
        
           
            | Server.cs using System;
 using System.Runtime.Remoting;
 
 public class Server{
 public static void Main(string[] Args){
 
 // Load the configuration file
 RemotingConfiguration.Configure("server.exe.config");
 
 Console.WriteLine("The server is listening. Press Enter to exit....");
 Console.ReadLine();
 
 Console.WriteLine("GC'ing.");
 GC.Collect();
 GC.WaitForPendingFinalizers();
 
 }
 }
 |    表1:Server.cs源代码 
 
        
           
            | Server.exe.config 
 <SYSTEM.RUNTIME.REMOTING>
 <APPLICATION>
 <SERVICE>
 <ACTIVATED type="ClientActivatedType, RemoteType">
 </SERVICE>
 <CHANNELS>
 <CHANNEL ref="http" port="8088">
 </CHANNELS>
 </APPLICATION>
 </SYSTEM.RUNTIME.REMOTING>
 </CONFIGURATION>
 |    表2:Server.exe.config源代码
 
        
           
            | RemoteType.cs using System;
 using System.Runtime.Remoting.Lifetime;
 using System.Security.Principal;
 
 public class ClientActivatedType : MarshalByRefObject{
 
 private int i;
 // override the lease settings for this object
 public override Object InitializeLifetimeService(){
 return null;
 }
 
 public string RemoteMethod(){
 
 // announce to the server that we've been called.
 Console.WriteLine("ClientActivatedType.RemoteMethod called.");
 
 // report our client identity name
 
 i=this.GetHashCode();
 return "RemoteMethod called. " + i;
 }
 
 public string RemoteMethod1(){
 return "RemoteMethod1 called. " + i;
 
 }
 }
 |    表3:RemoteType.cs源代码
 客户端代码
  
 
        
           
            | CAOClient.cs using System;
 using System.Runtime.Remoting;
 using System.Runtime.Remoting.Lifetime;
 
 public class Client{
 
 public static void Main(string[] Args){
 
 // Load the configuration file
 RemotingConfiguration.Configure("CAOclient.exe.config");
 
 ClientActivatedType CAObject = new ClientActivatedType();
 
 Console.WriteLine("Client-activated object: " + CAObject.RemoteMethod());
 Console.WriteLine("Client-activated object: " + CAObject.RemoteMethod1());
 
 Console.WriteLine("Press Enter to end the client application domain.");
 Console.ReadLine();
 }
 }
 |  表4 CAOClient.cs源代码
 
 
 
        
           
            | CAOClient.exe.config <CONFIGURATION>
 <SYSTEM.RUNTIME.REMOTING>
 <APPLICATION>
 <CLIENT url="http://localhost:8088">
 <ACTIVATED type="ClientActivatedType, RemoteType">
 </CLIENT>
 <CHANNELS>
 <CHANNEL ref="http" port="0">
 </CHANNELS>
 </APPLICATION>
 </SYSTEM.RUNTIME.REMOTING>
 </CONFIGURATION>
 |  表5:CAOClient.exe.config源代码
 
 编译文件
 
 使用“Visual Studio .NET Command Prompt="分别编译上述文件:
 
 
 
        
           
            | csc /target:library RemoteType.cs csc Server.cs
 csc –reference:RemoteType.dll CAOClient.cs
 您会看到三个输出文件:RemoteType.dll, Server.exe 和 CAOClient.exe。
 运行Remoting程序
 在命令行方式下启动:Server.exe
 在命令行方式下启动:CAOClient.exe
 |  程序分析
 
 这是一个非常简单的Remoting程序,如果去掉两个配置文件(Server.exe.config和CAOClient.exe.config),你简直看不到它和非Remoting的程序有什么差别。实际上,在两个配置文件中,我们只是配置了Remoting的Channel(http:8088)。
 为什么需要Remoting
 
 我们都知道现在的Web程序都是多层架构:数据层,商业逻辑层和表示层。这样的好处是代码和表现的分离。这是现在程序设计一个常用的思想,XML和XSLT也是基于同样的思想。
 
 假设我们可以为一个程序写两个表示层,一个是Web Application,另一个是Windows Application,而主要的商业逻辑都放在逻辑层。如果把商业逻辑层的类和对象都作为Remoting对象,我们就可以非常方便的实现这一点。一个具体的例子是Visual 
      Studio .NET自带的Duwamish,这是一个非常好的例子,有很多好的设计思想。
 
 Remoting还有很多其它的应用场景,在此就不一一阐述。
 
 三种不同的Remoting Server对象
 
 Remoting的Server对象有三种,每一种和客户端的交互方式和生命周期都有一些细微的差别。在本文中,我们将为您阐述这三种Server对象之间的差别。
 
 Client Activated 对象
 
 这种对象在Server端的声明方式为:
 
 
 
        
           
            | <SERVICE> <ACTIVATED type="ClientActivatedType, RemoteType">
 </SERVICE>
 |  客户端的声明方式为:
 
 <ACTIVATED type="ClientActivatedType, RemoteType">
 
 表6:Client Activated对象的配置文件
 
 在这种Server端对象的调用方式下,客户端对Server对象调用维持一个固定的链接,因此在两个方法调用之间,变量I的值能够保存。如本文表1~5代码的返回结果是:
 
 
 
        
           
            | Client-activated object: RemoteMethod Called, 
              162. Client-activated object: RemoteMethod1 Called, 162.
 |  当然,还有一个对象生命周期的问题,如果超过了对象的生命周期,Server端的对象就会被Garbage Collection程序回收。这是一个很复杂的问题,本文不加阐述,我们只是通过下面的函数把生命周期设为无限。
 
 
 
        
           
            | public override Object InitializeLifetimeService(){ return null;
 }
 |  如果对Server端对象的生命周期有兴趣的话,可以参考:
 
 
 
        
           
            | http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconlifetimeleases.asp Single Call 对象
 |  这种对象在Server端的声明方式为:
 
 
 
        
           
            | <SERVICE> <WELLKNOWN mode="SingleCall" type="ClientActivatedType, RemoteType" 
              objectUri="RemoteType.rem">
 </SERVICE>
 |  客户端的声明方式为:
 
 
 
        
           
            | <CLIENT url="http://localhost:8088"> <WELLKNOWN type="ClientActivatedType, RemoteType" url="HTTP://localhost:8088/RemoteType.rem">
 </CLIENT>
 |  表7:Single Call对象的配置文件
 
 在这种Server端对象的调用方式下,客户端对Server对象的每次调用产生一个新的连接,因此在两个方法调用之间,变量I的值不能够保存。如本文表1~5代码的返回结果是:
 
 
 
        
           
            | Client-activated object: RemoteMethod Called, 
              78. Client-activated object: RemoteMethod1 Called, 0.
 |  Singleton对象
 
 这种对象在Server端的声明方式为:
 
 
 
        
           
            | <SERVICE> <WELLKNOWN mode="Singleton" type="ClientActivatedType, RemoteType"
 objectUri="RemoteType.rem">
 </SERVICE>
 |  客户端的声明方式为:
 
 
 
        
           
            | <CLIENT url="http://localhost:8088"> <WELLKNOWN type="ClientActivatedType, RemoteType" url="HTTP://localhost:8088/RemoteType.rem">
 </CLIENT>
 |  表7:Single Call对象的配置文件
 
 在这种Server端对象的调用方式下,无论有几个客户端,永远都只有一个Server端对象。如本文表1~5代码的返回结果是:
 
 
 
        
           
            | Client-activated object: RemoteMethod Called, 
              78. Client-activated object: RemoteMethod1 Called, 78.
 |  这时,如果另外有一个客户端也启动:CAOClient.exe,返回结果也是:
 
 
 
        
           
            | Client-activated object: RemoteMethod Called, 
              78. Client-activated object: RemoteMethod1 Called, 78.
 |    三种对象的简单比较
 从上面的比较中我们可以看出,在三种Server端对象中,Singleton的效率最高,但是所有客户端的调用都只能维持一个Server对象;Client 
        Activated的效率最低,但是它对Remoting的屏蔽最好,就像本地调用对象一样。您可以根据不同的使用场景选择不同的Remoting对象。
 
 Remoting和Web Service区别
 
 Remoting和Web Servcie到底有什么样的差别呢?下表是一个简单的比较:
 
   由于Web Service是一个简单的松耦合结构,所以对于对象的状态不予保存。这一点有点像Remoting中的Single 
        Call对象。同样,Web Service目前还不支持Event和回调函数。相比较来说,Remoting还支持效率较高的Binary编码方式。
 但是,Remoting只能够运行在.NET Framework之上,而Web Service相应就享有更多、更灵活的选择。
 |