一,Remoting的定义
简单的说是一种分布式的处理方式。.Net Remoting提供了一个对象通过应用程序与另外一个对象进行通讯,交互的框架。
二,Remoting的过程概述
客户端通过Remoting访问通道(channel),获取服务端对象(只是对象的引用,不是实际的对象),再通过代理解析为客户端对象,序列化在客户端运行。
1,Remoting的两种通道:TCP(一般用于局域网,TcpChannel类型默认使用二进制格式序列化消息对象,因此它具有更高的传输性能。),HTTP(能在Internet上穿越防火墙传输序列化消息流。默认情况下,HttpChannel类型使用Soap格式序列化消息对象,因此它具有更好的互操作性。)
2,Remoting的激活模式:
(1)服务端激活:服务器应用程序在激活对象实例之前会在一个众所周知的统一资源标识符(URI)上来发布这个类型。然后该服务器进程会为此类型配置一个WellKnown对象,并根据指定的端口或地址来发布对象。
服务器端激活模式有:
a,SINGLETON模式,实例将在方法调用中一直维持其状态。举例来说,如果一个远程对象有一个累加方法(i=0;++i),被多个客户端(例如两个)调用。如果设置为SingleTon方式,则第一个客户获得值为1,第二个客户获得值为2,因为他们获得的对象实例是相同的。如果熟悉Asp.Net的状态管理,我们可以认为它是一种Application状态。
b,SINGLECALL模式,SingleCall是一种无状态模式。一旦设置为SingleCall模式,则当客户端调用远程对象的方法时,Remoting会为每一个客户端建立一个远程对象实例,至于对象实例的销毁则是由GC自动管理的。同上一个例子而言,则访问远程对象的两个客户获得的都是1。我们仍然可以借鉴Asp.Net的状态管理,认为它是一种Session状态。
(2) 客户端激活:与服务端激活不同,Remoting在激活每个对象实例的时候,会给每个客户端激活的类型指派一个URI。客户端激活模式一旦获得客户端的请求,将为每一个客户端都建立一个实例引用。SingleCall模式和客户端激活模式是有区别的:首先,对象实例创建的时间不一样。客户端激活方式是客户一旦发出调用的请求,就实例化;而SingleCall则是要等到调用对象方法时再创建。其次,SingleCall模式激活的对象是无状态的,对象生命期的管理是由GC管理的,而客户端激活的对象则有状态,其生命周期可自定义。其三,两种激活模式在服务器端和客户端实现的方法不一样。尤其是在客户端,SingleCall模式是由GetObject()来激活,它调用对象默认的构造函数。而客户端激活模式,则通过CreateInstance()来激活,它可以传递参数,所以可以调用自定义的构造函数来创建实例。
三,远程对象定义
客户端在获取服务器端对象时,并不是获得实际的服务端对象,而是获得它的引用。因此在Remoting中,对于远程对象有一些必须的定义规范要遵循。
由于Remoting传递的对象是以引用的方式,因此所传递的远程对象类必须继承MarshalByRefObject(MarshalByRefObject 是那些通过使用代理交换消息来跨越应用程序域边界进行通信的对象的基类)。
2 {
3 public Person GetPersonInfo(string name,string sex,int age)
4 {
5 Person person = new Person();
6 person.Name = name;
7 person.Sex = sex;
8 person.Age = age;
9 return person;
10 }
11 }
这个类只实现了最简单的方法,就是设置一个人的基本信息,并返回一个Person类对象。注意这里返回的Person类。由于这里所传递的Person则是以传值的方式来完成的,而Remoting要求必须是引用的对象,所以必须将Person类序列化。
因此,在Remoting中的远程对象中,如果还要调用或传递某个对象,例如类,或者结构,则该类或结构则必须实现串行化Attribute
2 [Serializable]
3 public class Person
4 {
5 public Person()
6 {
7
8 }
9
10 private string name;
11 private string sex;
12 private int age;
13
14 public string Name
15 {
16 get {return name;}
17 set {name = value;}
18 }
19
20 public string Sex
21 {
22 get {return sex;}
23 set {sex = value;}
24 }
25
26 public int Age
27 {
28 get {return age;}
29 set {age = value;}
30 }
31 }
将该远程对象以类库的方式编译成Dll。这个Dll将分别放在服务器端和客户端,以添加引用。
在Remoting中能够传递的远程对象可以是各种类型,包括复杂的DataSet对象,只要它能够被序列化。远程对象也可以包含事件,但服务器端对于事件的处理比较特殊。
四,服务端响应步骤
1,注册通道
ChannelServices.RegisterChannel(channel);
2,远程注册对象
(1)SINGLETON模式
2 typeof(ServerRemoteObject.ServerObject),
3 "ServiceMessage",WellKnownObjectMode.SingleTon);
(2)SINGLECALL模式
2 typeof(ServerRemoteObject.ServerObject),
3 "ServiceMessage",WellKnownObjectMode.SingleCall);
(3)客户端激活模式
2 RemotingConfiguration.RegisterActivatedServiceType(
3 typeof(ServerRemoteObject.ServerObject));
3,注销通道
2 IChannel[] channels = ChannelServices.RegisteredChannels;
3
4 //关闭指定名为MyTcp的通道;
5 foreach (IChannel eachChannel in channels)
6 {
7 if (eachChannel.ChannelName == "MyTcp")
8 {
9 TcpChannel tcpChannel = (TcpChannel)eachChannel;
10
11 //关闭监听;
12 tcpChannel.StopListening(null);
13
14 //注销通道;
15 ChannelServices.UnregisterChannel(tcpChannel);
16 }
17 }
五,客户端响应步骤
1,注册通道
2 ChannelServices.RegisterChannel(channel);
2,获得远程对象
(1)WELLKNOW模式
要获得服务器端的知名远程对象,可通过Activator进程的GetObject()方法来获得:
2 typeof(ServerRemoteObject.ServerObject), "tcp://localhost:8080/ServiceMessage");
(2)客户端模式
1) 调用RemotingConfiguration的静态方法RegisterActivatedClientType()。这个方法返回值为Void,它只是将远程对象注册在客户端而已。具体的实例化还需要调用对象类的构造函数。
2 typeof(ServerRemoteObject.ServerObject),
3 "tcp://localhost:8080/ServiceMessage");
4 ServerRemoteObject.ServerObject serverObj = new ServerRemoteObject.ServerObject();
2) 调用进程Activator的CreateInstance()方法。这个方法将创建方法参数指定类型的类对象。它与前面的GetObject()不同的是,它要在客户端调用构造函数,而GetObject()只是获得对象,而创建实例是在服务器端完成的。CreateInstance()方法有很多个重载,我着重说一下其中常用的两个。
a、 public static object CreateInstance(Type type, object[] args, object[] activationAttributes);
假设我们的远程对象类ServerObject有个构造函数:
2 {
3 name = pName;
4 sex = pSex;
5 age = pAge;
6 }
那么实现的代码是:
2 object[] objs = new object[3];
3 objs[0] = "wayfarer";
4 objs[1] = "male";
5 objs[2] = 28;
6 ServerRemoteObject.ServerObject = Activator.CreateInstance(
7 typeof(ServerRemoteObject.ServerObject),objs,attrs);
可以看到,objs[]数组传递的就是构造函数的参数。
b、public static ObjectHandle CreateInstance(string assemblyName, string typeName, object[] activationAttribute);
注意这个方法返回值为ObjectHandle类型,因此代码与前不同:
2 ObjectHandle handle = Activator.CreateInstance("ServerRemoteObject",
3 "ServerRemoteObject.ServerObject",attrs);
4 ServerRemoteObject.ServerObject obj = (ServerRemoteObject.ServerObject)handle.Unwrap();
这个方法实际上是调用的默认构造函数。ObjectHandle.Unwrap()方法是返回被包装的对象。
说明:要使用UrlAttribute,还需要在命名空间中添加:using System.Runtime.Remoting.Activation;
注:本文摘自http://www.cnblogs.com/wayfarer/archive/2004/07/30/28723.html 后自己整理的。