• .NET Remoting


    我们可以将其看作是一种分布式处理方式。
    .NET Remoting 提供了一种允许对象通过应用程序域与另一对象进行交互的框架。这也正是我们使用Remoting的原因。为什么呢?在Windows操作系统中,是将应用 程序分离为单独的进程。这个进程形成了应用程序代码和数据周围的一道边界。如果不采用进程间通信(RPC)机制,则在一个进程中执行的代码就不能访问另一 进程。这是一种操作系统对应用程序的保护机制。然而在某些情况下,我们需要跨过应用程序域,与另外的应用程序域进行通信,即穿越边界。
    在Remoting中是通过通道(channel)来实现两个应用程序域之间对象的通信的。
    两种通道:
           1,Tcp    
           2,Http
           System.Runtime.Remoting.Channel中定义了IChannel接口。IChannel接口包括了TcpChannel通道类型和Http通道类型
            TcpChannel类型放在名字空间System.Runtime.Remoting.Channel.Tcp中。Tcp通道提供了基于Socket的 传输工具,使用Tcp协议来跨越Remoting边界传输序列化的消息流。TcpChannel类型默认使用二进制格式序列化消息对象,因此它具有更高的 传输性能
            HttpChannel类型放在名字空间System.Runtime.Remoting.Channel.Http中。它提供了一种使用Http协议, 使其能在Internet上穿越防火墙传输序列化消息流。默认情况下,HttpChannel类型使用Soap格式序列化消息对象,因此它具有更好的互操 作性
            通常在局域网内,我们更多地使用TcpChannel;如果要穿越防火墙,则使用HttpChannel。
    
    二、远程对象的定义
    前面讲到,客户端在获取服务器端对象时,并不是获得实际的服务端对象,而是获得它的引用。因此在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的一部分。
    
    2、获得远程对象。
    与服务器端相同,不同的激活模式决定了客户端的实现方式也将不同。不过这个区别仅仅是WellKnown激活模式和客户端激活模式之间的区别,而对于SingleTon和SingleCall模式,客户端的实现完全相同。
    (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属性的内容。
  • 相关阅读:
    Map
    Enumeration输出
    iterator的基本用法
    Annotation整合工厂设计模式
    自定义Annotation
    Annotation
    动态代理设计模式
    静态代理设计模式
    自定义ClassLoader
    获取类的类对象的几种方式
  • 原文地址:https://www.cnblogs.com/rwh871212/p/6961724.html
Copyright © 2020-2023  润新知