Remoting技术简介

一 Remoting技术出现的背景

1)分布式应用需求的迅速增长(Peer-to-Peer, Grid等技术的出现)
2)原有的C/S, B/S模式和技术已经不能胜任(串口RS232,Socket,RPC,DCOM技术各有缺点)


二 什么是
Romoting?

采用分布式进行编程的一种技术,Remoting主要用于管理跨应用程序域的同步和异步RPC 会话。在默认情况下,Remoting使用 HTTP 或 TCP 协议,并使用 XML 编码的 SOAP 或本机二进制消息格式进行通信。.NET Remoting 提供了非常灵活和可扩展的编程框架,并且他可以管理对象的状态。

Remoting优点:
1)  性能: 如果调优.Net Remoting 的性能,那么他的性能非常好,速度接近DCOM.
2) 可扩展:.Net Remoting 可供你选择传输通道类型(如Http,Tcp)和格式类型(如Binary,Soap)。
3) 可配置:可以通过配置文件配置应用程序。
4) CLR和CTS的好处:由于.NET Remoting是基于.NET框架的,所以他拥有Common Type System(CTS) 和 Common Language Runtime(CLR)所拥有的易于使用和功能强大的特点。
5)互用性(Interoperability): .NET Remoting 支持开发标准(Http,SOAP,WSDL,XML).
6) 安全性
7) 生命周期管理


三 Remoting架构:

 Remoting通过通道(channel)来传输消息。.NET Remoting支持两种默认的协议支持通道(Http和Tcp).


四 远程对象的两个含义

操作远程对象:对象运行在远程,客户端向他发送消息.
传递远程对象:将远程的对象拿到本地,或者将本地对象发送过去,然后我们可以对副本进行操作.


五 激活对象的两种方式:
服务器激活和客户端激活

1 服务器激活:
“服务器激活的对象”是由服务器控制生存期的对象。它们只在客户端调用对象的第一个方法时,根据需要由服务器创建。服务器激活的对象只支持默认的构造函数。
代码:
2) SingleCall(单调用)
SingleCall 远程服务器类型总是为每个客户端请求设置一个实例。下一个方法调用将改由其他实例进行服务。从设计角度看,SingleCall 类型提供的功能非常简单。这种机制不提供状态管理,如果您需要状态管理,这将是一个不利之处;如果您不需要,这种机制将非常理想。也许您只关心负载平衡和可伸缩性而不关心状态,那么在这种情况下,这种模式将是您理想的选择,因为对于每个请求都只有一个实例。如果愿意,开发人员可以向 SingleCall 对象提供自己的状态管理,但这种状态数据不会驻留在对象中,因为每次调用新的方法时都将实例化一个新的对象标识。
特点:
a.每次调用都实例化新的实例
b.更好地支持无状态编程模型

2 客户端激活
“客户端激活的对象”是当客户端调用 newActivator.CreateInstance() 时在服务器上创建的。
代码:

<service>
  
<wellknown mode="SingleCall" type="Hello.HelloService, Hello" 
                   objectUri
="HelloService.soap" />
</service>

上面描述了一个服务器激活的 (wellknown) 类型,其激活方式设置为 SingleCall

服务器激活的对象有两种激活模式:SingletonSingleCall.
1) Singleton(单实例):
这些对象遵循传统的Singleton 设计模式,在这种模式中,任何时候内存中都只有一个实例,所有客户端都接受该实例提供的服务。
特点:
a.在服务器段只实例化一次,以后每次调用都访问同一个实例。
b.可以维持状态

<service>
  
<activated type="Hello.HelloService, Hello" 
             objectUri
="HelloService.soap" />
</service>

上面描述了一个客户端激活的类型。请注意,我们不再需要 URL,因为对于客户端激活的类型,类型本身就足以激活了。另外,wellknown 标记已被 activated 标记替代。

六 Remoting VS Web Service

这两者都是基于分布式的开发,而且.Net Remoting有时也可以配置为Web Service,两者有很多的相同之处。

一般来讲,我把他们的不同之处列为5个方面。

1) 开发部署
 WebService开发和部署比较简单,Remoting相对WebService开发和部署要稍复杂。
2) 协议的开放性 
    两者都可支持HTTP,TCP,SMTP等多种协议。
    [一直以为WebService只支持HTTP协议,经idior指点,原来在Web Services Enhancements已有介绍,WebService也支持TCP,SMTP等协议。微软最新发布的wse应该是wse 3.0,以前还没听说过,真是汗颜!]
   更详细的内容待续...
3) 支持的类型系统
 WebService只支持XSD类型系统,对象的类型的序列化受到限制,而Remoting可以通过序列化为Binary传输数据,支持更为广泛的数据类型
4) 安全性
 
由于 ASP.NET Web 服务依赖于 HTTP,因此它们与标准的 Internet 安全性基础结构相集成。ASP.NET 利用 IIS 的安全性功能,为标准 HTTP 验证方案(包括基本、简要、数字证书,甚至 Microsoft .NET Passport)提供了强有力的支持。
 一般情况下,.NET Remoting 管线不能确保跨进程调用的安全。使用 ASP.NET 托管于 IIS 中的 .NET Remoting 端点可以利用 ASP.NET Web 服务可用的所有安全性功能,包括对使用 SSL 确保有线通信的安全性的支持。
5) 性能
从原始性能方面来讲,使用 TCP 信道和二进制格式化程序时,.NET Remoting 管线能够提供最快的通信。一般情况下,.NET Remoting的性能要比WebService高。

 

下面的Remoting程序,采用了Singleton模式的服务器端激活的方式,分为三部分。
General:一个远程对象公用的程序集。
Server:服务器端
Client:客户端


一 创建第一个Remoting控制台程序

在创建程序之前,先把几个要用到的类先介绍一下:

1) MarshalByRefObject类:

允许在支持远程处理的应用程序中跨应用程序域边界访问对象。
应用程序域是一个操作系统进程中一个或多个应用程序所驻留的分区。同一应用程序域中的对象直接通信。不同应用程序域中的对象的通信方式有两种:一种是跨应用程序域边界传输对象副本,一种是使用代理交换消息。
MarshalByRefObject 是通过使用代理交换消息来跨应用程序域边界进行通信的对象的基类。不是从 MarshalByRefObject 继承的对象根据值隐式封送。当远程应用程序引用根据值封送的对象时,将跨应用程序域边界传递该对象的副本。
MarshalByRefObject 对象在本地应用程序域的边界内可直接访问。远程应用程序域中的应用程序首次访问 MarshalByRefObject 时,会向该远程应用程序传递代理。对该代理后面的调用将封送回驻留在本地应用程序域中的对象。
当跨应用程序域边界使用类型时,类型必须是从 MarshalByRefObject 继承的,而且由于对象的成员在创建它们的应用程序域之外无法使用,所以不得复制对象的状态。

2) ChannelServices 类:

提供帮助进行远程处理信道注册、解析和 URL 发现的静态方法。
信道跨远程处理边界(例如 AppDomains、进程和计算机)在应用程序之间传输消息。这些交叉可以是入站和出站的。信道可以在终结点上侦听入站消息,向终结点发送出站消息,或同时进行这两种操作。这在运行库中提供一个可扩展性点,以便插入各种协议,即使运行库可能并不在信道的另一端。运行库对象可用于公开各种语义和实体。信道提供可扩展性点以将消息在特定协议间来回转换。

3) TcpChannel 类:

一) Remoting程序的创建(分三步走)[附源代码下载].

1 创建General远程对象

此对象必须继承MarshalByRefObject。
代码如下:

2.创建Server作为"
宿主(host)",以接收客户请求

 1/// <summary>
 2    /// 远程对象类
 3    /// </summary>

 4    public class RemoteObject : MarshalByRefObject
 5    {
 6        public RemoteObject()
 7        {
 8            Console.WriteLine("I am from Remote Object!");
 9        }

10        public string GetClassName(string name)
11        {
12            return name;
13        }

14    }

 

1)注册通道,下文注册了一个端口号为8000的端口。
   注册后服务器就会监听来自8000端口的请求。

2)注册服务器激活的远程对象


3.创建Client,调用远程对象

 1/// <summary>
 2    /// 服务器端
 3    /// </summary>

 4    public class Server
 5    {
 6        static void Main(string[] args)
 7        {
 8            //实例化并注册一个TCP通道
 9            IChannel tcpchannel = new TcpChannel(8000);
10            ChannelServices.RegisterChannel(tcpchannel, true);
11
12            //将服务端上的对象类型注册为已知类型
13            RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteObject), "GetObject", WellKnownObjectMode.Singleton);
14
15            Console.WriteLine("Press Enter Key to Exit!");
16            Console.ReadLine();
17      
18        }

19    }

 

1)注册通道
2)根据URL得到对象代理
3)使用代理调用远程对象

 1/// <summary>
 2    /// 客户端
 3    /// </summary>

 4    public class Client
 5    {
 6        static void Main(string[] args)
 7        {
 8            //实例化并注册一个TCP通道
 9            IChannel tcpChannel = new TcpChannel();
10            ChannelServices.RegisterChannel(tcpChannel, true);
11
12            //激活远程对象
13            RemoteObject obj = (RemoteObject)Activator.GetObject(typeof(RemotingDemo.RemoteObject),"tcp://localhost:8000/GetObject");
14
15            if (obj == null)
16            {
17                Console.WriteLine("Could not get Tcp Server");
18            }

19
20            //调用远程方法
21            Console.WriteLine("Client TCP GetClassName: {0}",obj.GetClassName("ring1981"));
22
23            Console.ReadLine();
24        }

25    }


到此为止,Remoting应用程序建立完毕!

运行结果:

上面的例子是全部通过编程实现,在下篇文章里里我会介绍如何通过配置文件实现。

二)关于运行Remoting程序的一点说明

由于不少初学者说按"F5"看不到这样的结果,其实是没有学会如何运行这种多个项目,出现多个Dos窗口结果的工程。

我就附带介绍一下如何运行上面这个例子吧:
第一步: 选择"Debug"->"Start Debuging"或"Debug->Start without Debug"都行,点击后会出现一个Dos窗口显示结果。
第二步: 选择"Soluting Explorer"下的"Client"项目,选中后点击鼠标右键,点击后出现一个菜单。
第三步: 选择"Debug"->"Start new instance",单击就OK了。
 

二 使用配置文件建立Remoting程序


一) 服务器端配置(app.config)

 1<configuration>
 2  <system.runtime.remoting>
 3    <application>
 4      <channels>
 5        <channel ref="tcp" port="8000" />
 6      </channels>
 7      <service>
 8        <wellknown mode="Singleton"
 9                   type="RemotingDemo.RemoteObject, General"
10                   objectUri="GetObject" />
11      </service>
12    </application>
13  </system.runtime.remoting>
14</configuration>
15


此时服务器端代码为:

 1 /// <summary>
 2    /// 服务器端
 3    /// </summary>

 4    public class Server
 5    {
 6        static void Main(string[] args)
 7        {            
 8            RemotingConfiguration.Configure("server.exe.config"true);
 9
10            Console.WriteLine("Press Enter Key to Exit!");
11            Console.ReadLine();      
12        }

13    }



二) 客户端配置 (client.exe.config)

 1<configuration>
 2    <system.runtime.remoting>
 3        <application>
 4            <client>
 5                <wellknown type="RemoteObject, General" url="tcp://localhost:8000/GetObject" />
 6            </client>
 7            <channels>
 8                <channel ref="tcp" port="0"></channel>
 9            </channels>
10        </application>
11    </system.runtime.remoting>
12</configuration>
13


此时客户端的代码为:

/// <summary>
    
/// 客户端
    
/// </summary>

    public class Client
    
{
        
static void Main(string[] args)
        
{
            
            RemotingConfiguration.Configure(
@"client.exe.config"true);
            RemoteObject obj 
= new RemoteObject();
            
if (obj == null)
            
{
                Console.WriteLine(
"Could not get Tcp Server");
            }


            
//调用远程方法
            Console.WriteLine("Client TCP GetClassName: {0}",obj.GetClassName("ring1981"));

            Console.ReadLine();
        }

    }



一个标准写全的Remoting Configuration文件应该是如下结构:

 1<configuration>
 2   <system.runtime.remoting>
 3      <application>
 4        <lifetime />
 5        <channels />
 6        <service />
 7        <client />
 8      </application>
 9   </system.runtime.remoting>
10</configuration>
11
12


接下来结合配置文件介绍一下各结点的具体涉及内容:

一) 生命周期(LifeTime):用于配置对象的生命周期.

ATTRIBUTE

DESCRIPTION

leaseTime

The initial time to live (TTL) for your objects (默认5 分钟)

sponsorshipTimeout

The time to wait for a sponsor's reply (默认2 分钟)

renewOnCallTime

The time to add to an object's TTL when a method is called (默认2 分钟)

leaseManagerPollTime

The interval in which your object's TTL will be checked (默认10 秒)

ATTRIBUTE

DESCRIPTION

ref

引用先前定义好的通道("tcp"或"http"),或者引用先前在配置文件里定义好的通道

displayName

此属性只用于.NET Framework配置工具

type

该属性在ref没有定义时,是托管的。Attribute that is mandatory when ref has not been specified. Contains the exact type (namespace, classname, assembly) of the channel's implementation. When the assembly is in the GAC, you have to specify version, culture, and public key information as well.

port

端口号

ATTRIBUTE

DESCRIPTION

type

写法如"<namespace>.<classname>, <assembly>"。程序集中已发布类的类型。

mode

指出具体对象调用类型("Singleton" 或"SingleCall").

objectUri

用于呼叫对象的终端URI。当对象宿主在IIS中,URI需以.soap或.rem结尾。

displayName

用于.NET Framework Configuration Tool中。

ATTRIBUTE

DESCRIPTION

type

写法如"<namespace>.<classname>, <assembly>"。程序集中已发布类的类型。

提供使用 TCP 协议传输消息的信道实现。