Remoting

一、      Remoting基础

什么是Remoting,简而言之,我们可以将其看作是一种分布式处理方式。从微软的产品角度来看,可以说Remoting就是DCOM的一种升级,它改善了很多功能,并极好的融合到.Net平台下。Microsoft® .NET Remoting 提供了一种允许对象通过应用程序域与另一对象进行交互的框架。这也正是我们使用Remoting的原因。为什么呢?在Windows操作系统中,是将应用程序分离为单独的进程。这个进程形成了应用程序代码和数据周围的一道边界。如果不采用进程间通信(RPC)机制,则在一个进程中执行的代码就不能访问另一进程。这是一种操作系统对应用程序的保护机制。然而在某些情况下,我们需要跨过应用程序域,与另外的应用程序域进行通信,即穿越边界。

在Remoting中是通过通道(channel)来实现两个应用程序域之间对象的通信的。如图所示:

首先,客户端通过Remoting,访问通道以获得服务端对象,再通过代理解析为客户端对象。这就提供一种可能性,即以服务的方式来发布服务器对象。远程对象代码可以运行在服务器上(如服务器激活的对象和客户端激活的对象),然后客户端再通过Remoting连接服务器,获得该服务对象并通过序列化在客户端运行。

在Remoting中,对于要传递的对象,设计者除了需要了解通道的类型和端口号之外,无需再了解数据包的格式。但必须注意的是,客户端在获取服务器端对象时,并不是获得实际的服务端对象,而是获得它的引用。这既保证了客户端和服务器端有关对象的松散耦合,同时也优化了通信的性能。

1、   Remoting的两种通道

Remoting的通道主要有两种:Tcp和Http。在.Net中,System.Runtime.Remoting.Channel中定义了IChannel接口。IChannel接口包括了TcpChannel通道类型和Http通道类型。它们分别对应Remoting通道的这两种类型。

TcpChannel类型放在名字空间System.Runtime.Remoting.Channel.Tcp中。Tcp通道提供了基于Socket的传输工具,使用Tcp协议来跨越Remoting边界传输序列化的消息流。TcpChannel类型默认使用二进制格式序列化消息对象,因此它具有更高的传输性能。HttpChannel类型放在名字空间System.Runtime.Remoting.Channel.Http中。它提供了一种使用Http协议,使其能在Internet上穿越防火墙传输序列化消息流。默认情况下,HttpChannel类型使用Soap格式序列化消息对象,因此它具有更好的互操作性。通常在局域网内,我们更多地使用TcpChannel;如果要穿越防火墙,则使用HttpChannel。

2、远程对象的激活方式

在访问远程类型的一个对象实例之前,必须通过一个名为Activation的进程创建它并进行初始化。这种客户端通过通道来创建远程对象,称为对象的激活。在Remoting中,远程对象的激活分为两大类:服务器端激活和客户端激活。

1) 服务器端激活,又叫做WellKnow方式,很多又翻译为知名对象。为什么称为知名对象激活模式呢?是因为服务器应用程序在激活对象实例之前会在一个众所周知的统一资源标识符(URI)上来发布这个类型。然后该服务器进程会为此类型配置一个WellKnown对象,并根据指定的端口或地址来发布对象。.Net Remoting把服务器端激活又分为SingleTon模式和SingleCall模式两种。

SingleTon模式:此为有状态模式。如果设置为SingleTon激活方式,则Remoting将为所有客户端建立同一个对象实例。当对象处于活动状态时,SingleTon实例会处理所有后来的客户端访问请求,而不管它们是同一个客户端,还是其他客户端。SingleTon实例将在方法调用中一直维持其状态。举例来说,如果一个远程对象有一个累加方法(i=0;++i),被多个客户端(例如两个)调用。如果设置为SingleTon方式,则第一个客户获得值为1,第二个客户获得值为2,因为他们获得的对象实例是相同的。如果熟悉Asp.Net的状态管理,我们可以认为它是一种Application状态。

SingleCall模式:SingleCall是一种无状态模式。一旦设置为SingleCall模式,则当客户端调用远程对象的方法时,Remoting会为每一个客户端建立一个远程对象实例,至于对象实例的销毁则是由GC自动管理的。同上一个例子而言,则访问远程对象的两个客户获得的都是1。我们仍然可以借鉴Asp.Net的状态管理,认为它是一种Session状态。

(2) 客户端激活。与WellKnown模式不同,Remoting在激活每个对象实例的时候,会给每个客户端激活的类型指派一个URI。客户端激活模式一旦获得客户端的请求,将为每一个客户端都建立一个实例引用。SingleCall模式和客户端激活模式是有区别的:首先,对象实例创建的时间不一样。客户端激活方式是客户一旦发出调用的请求,就实例化;而SingleCall则是要等到调用对象方法时再创建。其次,SingleCall模式激活的对象是无状态的,对象生命期的管理是由GC管理的,而客户端激活的对象则有状态,其生命周期可自定义。其三,两种激活模式在服务器端和客户端实现的方法不一样。尤其是在客户端,SingleCall模式是由GetObject()来激活,它调用对象默认的构造函数。而客户端激活模式,则通过CreateInstance()来激活,它可以传递参数,所以可以调用自定义的构造函数来创建实例。

二、远程对象的定义

前面讲到,客户端在获取服务器端对象时,并不是获得实际的服务端对象,而是获得它的引用。因此在Remoting中,对于远程对象有一些必须的定义规范要遵循。

由于Remoting传递的对象是以引用的方式,因此所传递的远程对象类必须继承MarshalByRefObject。MSDN对MarshalByRefObject的说明是:MarshalByRefObject 是那些通过使用代理交换消息来跨越应用程序域边界进行通信的对象的基类。不是从 MarshalByRefObject 继承的对象会以隐式方式按值封送。当远程应用程序引用一个按值封送的对象时,将跨越远程处理边界传递该对象的副本。因为您希望使用代理方法而不是副本方法进行通信,因此需要继承MarshallByRefObject。

以下是一个远程对象类的定义:
public class ServerObject:MarshalByRefObject
{
        public Person GetPersonInfo(string
name,string sex,int age)
        {
            Person
person = new Person();
            person.Name
= name;
            person.Sex =
sex;
            person.Age =
age;
            return
person;
        }
}

这个类只实现了最简单的方法,就是设置一个人的基本信息,并返回一个Person类对象。注意这里返回的Person类。由于这里所传递的Person则是以传值的方式来完成的,而Remoting要求必须是引用的对象,所以必须将Person类序列化。

因此,在Remoting中的远程对象中,如果还要调用或传递某个对象,例如类,或者结构,则该类或结构则必须实现串行化Attribute[SerializableAttribute]:
[Serializable]
public class Person
{
        public Person()
        {
           
        }

private string
name;
        private string sex;
        private int age;

public string
Name
        {
            get   
{return name;}
           
set    {name = value;}
        }

public string
Sex
        {
            get {return
sex;}
            set {sex =
value;}
        }

public int Age
        {
            get {return
age;}
            set {age =
value;}
        }
   }

将该远程对象以类库的方式编译成Dll。这个Dll将分别放在服务器端和客户端,以添加引用。

在Remoting中能够传递的远程对象可以是各种类型,包括复杂的DataSet对象,只要它能够被序列化。远程对象也可以包含事件,但服务器端对于事件的处理比较特殊,我将在本系列之三中介绍。

三、服务器端

根据第一部分所述,根据激活模式的不同,通道类型的不同服务器端的实现方式也有所不同。大体上说,服务器端应分为三步:

1、注册通道

要跨越应用程序域进行通信,必须实现通道。如前所述,Remoting提供了IChannel接口,分别包含TcpChannel和HttpChannel两种类型的通道。这两种类型除了性能和序列化数据的格式不同外,实现的方式完全一致,因此下面我们就以TcpChannel为例。

注册TcpChannel,首先要在项目中添加引用“System.Runtime.Remoting”,然后using名字空间:System.Runtime.Remoting.Channel.Tcp。代码如下:
            TcpChannel
channel = new TcpChannel(8080);
           
ChannelServices.RegisterChannel(channel);

在实例化通道对象时,将端口号作为参数传递。然后再调用静态方法RegisterChannel()来注册该通道对象即可。

2、注册远程对象

注册了通道后,要能激活远程对象,必须在通道中注册该对象。根据激活模式的不同,注册对象的方法也不同。

(1) SingleTon模式

对于WellKnown对象,可以通过静态方法RemotingConfiguration.RegisterWellKnownServiceType()来实现:RemotingConfiguration.RegisterWellKnownServiceType(
               
typeof(ServerRemoteObject.ServerObject),
               
"ServiceMessage",WellKnownObjectMode.SingleTon);

(2)SingleCall模式

注册对象的方法基本上和SingleTon模式相同,只需要将枚举参数WellKnownObjectMode改为SingleCall就可以了。RemotingConfiguration.RegisterWellKnownServiceType(
               
typeof(ServerRemoteObject.ServerObject),
               
"ServiceMessage",WellKnownObjectMode.SingleCall);

(3)客户端激活模式

对于客户端激活模式,使用的方法又有不同,但区别不大,看了代码就一目了然。
RemotingConfiguration.ApplicationName = "ServiceMessage";
RemotingConfiguration.RegisterActivatedServiceType(
               
typeof(ServerRemoteObject.ServerObject));

为什么要在注册对象方法前设置ApplicationName属性呢?其实这个属性就是该对象的URI。对于WellKnown模式,URI是放在RegisterWellKnownServiceType()方法的参数中,当然也可以拿出来专门对ApplicationName属性赋值。而RegisterActivatedServiceType()方法的重载中,没有ApplicationName的参数,所以必须分开。

3、注销通道

如果要关闭Remoting的服务,则需要注销通道,也可以关闭对通道的监听。在Remoting中当我们注册通道的时候,就自动开启了通道的监听。而如果关闭了对通道的监听,则该通道就无法接受客户端的请求,但通道仍然存在,如果你想再一次注册该通道,会抛出异常。

//获得当前已注册的通道;
            IChannel[]
channels = ChannelServices.RegisteredChannels;

//关闭指定名为MyTcp的通道;
            foreach
(IChannel eachChannel in channels)
            {
               
if (eachChannel.ChannelName == "MyTcp")
               
{
                   
TcpChannel tcpChannel = (TcpChannel)eachChannel;

//关闭监听;
                   
tcpChannel.StopListening(null);

//注销通道;
                   
ChannelServices.UnregisterChannel(tcpChannel);
               
}
            }
代码中,RegisterdChannel属性获得的是当前已注册的通道。在Remoting中,是允许同时注册多个通道的,这一点会在后面说明。

四、客户端

客户端主要做两件事,一是注册通道。这一点从图一就可以看出,Remoting中服务器端和客户端都必须通过通道来传递消息,以获得远程对象。第二步则是获得该远程对象。

1、注册通道:
TcpChannel channel = new TcpChannel();
ChannelServices.RegisterChannel(channel);

注意在客户端实例化通道时,是调用的默认构造函数,即没有传递端口号。事实上,这个端口号是缺一不可的,只不过它的指定被放在后面作为了Uri的一部分。

(1) WellKnown激活模式

要获得服务器端的知名远程对象,可通过Activator进程的GetObject()方法来获得:
ServerRemoteObject.ServerObject serverObj = (ServerRemoteObject.ServerObject)Activator.GetObject(
             
typeof(ServerRemoteObject.ServerObject),
"tcp://localhost:8080/ServiceMessage");

首先以WellKnown模式激活,客户端获得对象的方法是使用GetObject()。其中参数第一个是远程对象的类型。第二个参数就是服务器端的uri。如果是http通道,自然是用http://localhost:8080/ServiceMessage了。因为我是用本地机,所以这里是localhost,你可以用具体的服务器IP地址来代替它。端口必须和服务器端的端口一致。后面则是服务器定义的远程对象服务名,即ApplicationName属性的内容。

(2) 客户端激活模式

如前所述,WellKnown模式在客户端创建对象时,只能调用默认的构造函数,上面的代码就说明了这一点,因为GetObject()方法不能传递构造函数的参数。而客户端激活模式则可以通过自定义的构造函数来创建远程对象。

客户端激活模式有两种方法:

1) 调用RemotingConfiguration的静态方法RegisterActivatedClientType()。这个方法返回值为Void,它只是将远程对象注册在客户端而已。具体的实例化还需要调用对象类的构造函数。
RemotingConfiguration.RegisterActivatedClientType(               
               
typeof(ServerRemoteObject.ServerObject),
               
"tcp://localhost:8080/ServiceMessage");
ServerRemoteObject.ServerObject serverObj = new
ServerRemoteObject.ServerObject();

2) 调用进程Activator的CreateInstance()方法。这个方法将创建方法参数指定类型的类对象。它与前面的GetObject()不同的是,它要在客户端调用构造函数,而GetObject()只是获得对象,而创建实例是在服务器端完成的。CreateInstance()方法有很多个重载,我着重说一下其中常用的两个。
a、 public static object CreateInstance(Type type,
object[] args, object[] activationAttributes);

参数说明:

type:要创建的对象的类型。

args :与要调用构造函数的参数数量、顺序和类型匹配的参数数组。如果 args 为空数组或空引用(Visual Basic 中为 Nothing),则调用不带任何参数的构造函数(默认构造函数)。

activationAttributes :包含一个或多个可以参与激活的属性的数组。

这里的参数args是一个object[]数组类型。它可以传递要创建对象的构造函数中的参数。从这里其实可以得到一个结论:WellKnown激活模式所传递的远程对象类,只能使用默认的构造函数;而Activated模式则可以用户自定义构造函数。activationAttributes参数在这个方法中通常用来传递服务器的url。

假设我们的远程对象类ServerObject有个构造函数:

ServerObject(string pName,string pSex,int pAge)
            {
               
name = pName;
               
sex = pSex;
               
age = pAge;
            }

那么实现的代码是:
            object[]
attrs = {new UrlAttribute("tcp://localhost:8080/ServiceMessage")};
            object[]
objs = new object[3];
            objs[0] =
"wayfarer";
            objs[1] =
"male";
            objs[2] =
28;
           
ServerRemoteObject.ServerObject = Activator.CreateInstance(
               
typeof(ServerRemoteObject.ServerObject),objs,attrs);
可以看到,objs[]数组传递的就是构造函数的参数。

b、public static ObjectHandle
CreateInstance(string assemblyName, string typeName, object[]
activationAttribute);

参数说明:
assemblyName :将在其中查找名为 typeName 的类型的程序集的名称。如果 assemblyName 为空引用(Visual Basic 中为 Nothing),则搜索正在执行的程序集。
typeName:首选类型的名称。
activationAttributes :包含一个或多个可以参与激活的属性的数组。

参数说明一目了然。注意这个方法返回值为ObjectHandle类型,因此代码与前不同:
            object[]
attrs = {new
UrlAttribute("tcp://localhost:8080/EchoMessage")};           
            ObjectHandle
handle = Activator.CreateInstance("ServerRemoteObject",
                                  
"ServerRemoteObject.ServerObject",attrs);
           
ServerRemoteObject.ServerObject obj =
(ServerRemoteObject.ServerObject)handle.Unwrap();

这个方法实际上是调用的默认构造函数。ObjectHandle.Unwrap()方法是返回被包装的对象。

说明:要使用UrlAttribute,还需要在命名空间中添加:using System.Runtime.Remoting.Activation;

时间: 2024-10-27 05:14:28

Remoting的相关文章

.Net remoting学习笔记

.NET Remoting是.NET平台上允许存在于不同应用程序域中的对象之间进行通讯的基础设施.调用对象被称为客户端,而被调用对象则被称为服务器或者服务器对象.简而言之,它就是.NET平台上实现分布式对象系统的框架. 传统的方法调用是通过栈实现,调用方法前将this指针以及方法参数压入线程栈中,线程执行方法时将栈中的参数取出作为本地变量,经过一番计算后,将方法的返回结果压入栈中.这样我们就完成了一次方法调用. 基于栈的方法调用在同一个应用程序域中很容易实现,但是如果要调用的方法所属的对象位于另

Remoting示例

通过Remoting,客户端可以借助远程对象的代理对象,完成服务端的操作,下面是一个最初的demo,深入学习可以参考链接: http://www.cnblogs.com/xia520pi/archive/2011/11/02/2233371.html 服务端: static void Main(string[] args) { //在服务器端创建TcpServerChannel信道 var channel = new TcpServerChannel(8086); //注册该信道,使之可用于远程

.Net remoting方法实现简单的在线升级(上篇:更新文件)

一.前言:       最近做一个简单的在线升级Demo,使用了微软较早的.Net Remoting技术来练手. 简单的思路就是在服务器配置一个Remoting对象,然后在客户端来执行Remoting对象中的方法. 过程: (1) 读取本地dll文件的名称与版本号,与服务器的进行对比 (2) 确认需要升级的文件名称与版本号并告诉服务器,服务器将其复制到一个临时文件夹并压缩成zip (3) 将服务器的zip下载到本地的临时文件夹,并解压. 定义服务器端为UpdateServer,其配置文件为: <

写手Remoting测试工具

基于.NET开发分布式系统.经经常使用到Remoting技术.在測试驱动开发流行的今天.假设针对分布式系统中的每一个Remoting接口的每一个方法都要写具体的測试脚本,无疑很浪费时间.所以,我想写一个能自己主动測试remoting接口的小工具InterfaceTester.并且.当分布式系统中的某个remoting接口出现bug时.该小工具能够提交须要模拟的数据,以便在调试remoting服务的环境中.高速定位和解决bug. InterfaceTester执行起来后的效果例如以下图: 1.怎样

WCF分布式开发必备知识(2):.Net Remoting

.Net Remoting技术,我们可以将其看作是一种分布式处理方式.作为应用程序之间通信的一种机制,.Net Remoting与MSMQ消息队列不同,它不支持离线脱机消息,另外只适合.Net平台间程序的通信.从微软的产品角度来看,可以说Remoting就是分布式组件DCOM的一种升级,它改善了很多功能,并极好的融合到.Net平台下..NET Remoting 提供了一种允许对象通过应用程序域与另一对象进行交互的框架.这也正是我们使用Remoting的原因.为什么呢?在Windows操作系统中,

.net remoting

.net remoting 之了解: http://www.cnblogs.com/WangJinYang/archive/2013/01/17/2864890.html .NET Remoting 体系结构 之 信道的功能和配置 (一) http://www.cnblogs.com/WangJinYang/archive/2013/01/20/2868664.html .NET Remoting 体系结构 之 信道的功能和配置 (二) http://www.cnblogs.com/WangJi

何为.Net Remoting【转】

借助基维百科给它的定义如下: NET Remoting 是微软 .NET Framework 中的一种网络通讯技术,与 XML Web Service 不同的是,它可以使用 SOAP 以外的协定来通讯,而在伺服端和用户端之间所操作的方法近乎相同,用户端可以不必考虑使用的协定,即可存取伺服端所开放的物件.这个技术与是由Distributed COM所发展而来的,与DCOM最大的不同是,DCOM有限制使用 TCP Port,但.NET Remoting 可以选择使用 TCP 或 HTTP 的方式通讯

.net core 2.0学习笔记(六):Remoting核心类库RealProxy迁移

在学习.net core的过程中,我们已经明确被告知,Remoting将不会被支持.官方的解释是,.net framework 类型包含了太多的Runtime的内容,是一个非常重量级的服务实现,已被确定为一项有问题的体系结构.说白了就是迁移的难度很大,.net core中直接不提供了.微软的建议是,如果是进程内或跨进程通讯,建议我们使用 Pipes或者内存映射文件(Memory Mapped Files).如果是机器间的调用,建议我们采用网络通讯的方案,比如HTTP.WCF等. 好吧,既然微软官

Castle 整合.NET Remoting

今天研究了一下Castle的Remoting Facility.记录如下: 微软以前使用COM/DCOM的技术来处理分布式系统架构,通过Client端的Proxy代理程序来呼叫远程Server机器上的对象..NET Framework则使用.NET Remoting或Web Services技术来实作分布式处理的工作概念:在这里针对.NET Remoting的设计架构做一个初步的简介和Castle整合示例. .NET Framework提供了多种的机制来支持Remoting,如: .利用Chan

C# Remoting 简单实现

此处下载源代码(VS2010编译通过)   http://files.cnblogs.com/files/qqhfeng/%E8%BF%9C%E7%A8%8B%E8%B0%83%E7%94%A8%E6%B5%8B%E8%AF%952.rar RemotingModel: Talker.cs using System; using System.Collections.Generic; using System.Text; namespace RemotingModel { /// <summar