蓝天旭日

高手如云,自己只是个菜鸟而已! 没有人在意你曾经的努力和散漫,只有人关注你是否有成就......
  博客园  :: 首页  :: 新随笔  :: 联系 :: 管理

数据通讯之Microsoft .Net Remoting入门(1)

Posted on 2007-12-29 19:03  蓝天旭日  阅读(1605)  评论(0编辑  收藏  举报
          谈到数据通讯,大家首先想到的是socket,因为它更面向底层,使用socket效率也比较高,但是就效率而言,socket并不是一个很好的选择,最大的问题是需要硬编码,传过去的数据包需要按位解析等。

      Remoting, 它让你把本来通过Socket做的并且还比较复杂的事情简单化了,在.NET的世界中,如果要跨应用程序域(AppDomain),或者跨进程(Process)、跨机器进行面向对象的调用, Remoting技术把对象/接口方法调用消息化,通过对用户透明的机制来实现跨AppDomain边界的消息传递和翻译。典型的,在跨机器的情景下,.NET   Remoting把这个透明机制绑定到一个TCP端口上(也可以使用HTTP),看起来就特别像Socket调用,但实际上完全不是一回事。Socket仅仅是一种纯粹的、协议层面上的通讯技术,但Remoting给与你更多。除了跨AppDomain的面向对象调用,Remoting还允许你通过消息截获机制,实现.NET风格的AOP,不过这个说起来就比较远了……

     闲话不说了,首先我门来进行一个小例子,通过这个例子之后,我们再讲解其它事项!

第一步:建议server端程序:

1 项目新建控制台程序--

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

using System.Security.Permissions;

public class Server

{

    [SecurityPermission(SecurityAction.Demand)]

    public static void Main(string[] args)

    {

        TcpChannel serverChannel = new TcpChannel(8081);// 8081为为端口号

        ChannelServices.RegisterChannel(serverChannel, true);//注册通道

        //注册远程对象

        RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteTest), "proname", WellKnownObjectMode.Singleton);

       

        Console.WriteLine("Press any KEY to exit the server and stop the channel.");  

        Console.ReadLine();

        serverChannel.StopListening(null); //停止监听

        ChannelServices.UnregisterChannel(serverChannel); //注销通道

    }

}

第二步:建议client端程序:

项目新建控制台程序---

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

using System.Security.Permissions;

public class Client

{

    [SecurityPermission(SecurityAction.Demand)]

    public static void Main(string[] args)

    {

      

        TcpChannel clientChannel = new TcpChannel(); //创建通道

       

        ChannelServices.RegisterChannel(clientChannel,true);//注册通道

        //获取远程对象

       //(1) WellKnown激活模式调用RemotingConfiguration的静态方法RegisterActivatedClientType()。

        /*WellKnownClientTypeEntry remoteType = new WellKnownClientTypeEntry(typeof(RemoteTest), "tcp://192.168.168.165:9090/RemoteObject.rem");

       RemotingConfiguration.RegisterWellKnownClientType(RemoteTest);

      

       RemoteTest obj2 = new RemoteTest(); */

        //客户端激活模式()调用Activator进程的GetObject()方法

        RemoteTest obj2 = (RemoteTest)Activator.GetObject(typeof(RemoteTest), "tcp://192.168.168.165:8081/ proname ");

  

        person m = new person("TempUser", "men", "19");

        m = obj2.getInfo(m);

        Console.WriteLine(m.name);

     

        Console.Read();

    }

}

注意看上面代码,两段程序代码里面反复出现RemoteTest,person等字眼,一看就知道这两个是大家自己定义的类,马上我们建立它,“tcp://192.168.168.165:8081/proname”,其中,tcp代表的tcp协议,如果是http当然就应该上http协议了,后面是IP地址和端口号,即服务器端的地址和端口号,后面的proname叫做远程对象服务名,我们暂且不记它,只要保持一致就可以了,其实在程序中对应ApplicationName属性的内容。

回到主题上来,刚才的RemoteTest,person等类都没有,直接编译肯定出错,怎么办,马上解决。

 

第二步:建议远程服务对象:

项目新建控制台程序

 注意,这次建立的不需要运行,直接编译成dll文件即可,然后在服务器端和客户端分别添加引用即可,代码如下:

using System;

using System.Runtime.Remoting;

// Remote object.

public class RemoteTest : MarshalByRefObject

{

    private int clientCount = 0;

    public int ReCount(int i)

    {

        clientCount = (clientCount++)+i;

        return (clientCount);

    }

    public string HelloWorld(string name)

    {

        Console.WriteLine("GOOD MORNING!");

        return "Hi," + name;

    }

    public person getInfo(person m)

    {

        Console.WriteLine("THERE HAVE ONE PERSON INFOMATION HAS RESIVED!");

       

        Console.WriteLine(m.name+"-"+m.age+"-"+m.sex);

        person p = new person(m.name, m.sex, m.age);

        return p;

    }

}

[Serializable//必须进行序列化

public class person

{

    public person(string name, string sex, string age)

    {

        this.name = name;

        this.sex = sex;

        this.age = age;

        Console.WriteLine("--------------------------------------");

       

    }

    public string name;

    public string sex;

    public string age;

}

文件中有很多我们没有办法知道的字眼和,我们也不知道干什么的,不过毕竟是例子,暂且不管.

以后你会知道,RemoteTest是服务器端和客户端都要用的远程对象,person是我们传输对象的一个例子而已。

   因为没有做捕获异常等处理,先运行服务器端,服务器端显示

Press any KEY to exit the server and stop the channel.

THERE HAVE ONE PERSON INFOMATION HAS RESIVED!

               //下面两行是客户端运行后服务器端增加显示的内容

TempUser-19-men

--------------------------------------

再运行客户端。客户端显示

--------------------------------------

TempUser

    以上是一个简单的remoting通讯的例子,我自定义了一个person类,两边分别传递,

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

 今天首先记住几个重要步骤:

a 必须添加如下引用

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

using System.Security.Permissions;

服务器端

 1 注册通道 :    

 TcpChannel serverChannel = new TcpChannel(8081)

ChannelServices.RegisterChannel(clientChannel,true);

2  注册远程对象 :

             RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteTest), "proname", WellKnownObjectMode.Singleton);

注销通道:

           serverChannel.StopListening(null); //停止监听

        ChannelServices.UnregisterChannel(serverChannel); //注销通道

         

C 客户端

 1 注册通道

     TcpChannel clientChannel = new TcpChannel(); //创建通道

       

        ChannelServices.RegisterChannel(clientChannel,true);//注册通道

2  获得远程对象

     RemoteTest obj2 = (RemoteTest)Activator.GetObject(typeof(RemoteTest), "tcp://192.168.168.165:8081/ proname ");

还有也可以如下方式获得:

 RegisterActivatedClientType()

        /*WellKnownClientTypeEntry remoteType = new WellKnownClientTypeEntry(typeof(RemoteTest), "tcp://192.168.168.165:9090/RemoteObject.rem");

       RemotingConfiguration.RegisterWellKnownClientType(RemoteTest);

      

       RemoteTest obj2 = new RemoteTest(); */

即WellKnown激活模式调用RemotingConfiguration的静态方法,

d  远程对象

  编译成dll,分别在服务器和客户端添加引用,注意传输的对象必须[Serializable]序列化,远程对象必须继承MarshalByRefObject

  以上就是我们对remoting的一个初步讲解,至于后期如何响应事件啊,如何激活远程对象和remoting的原理和分解,下篇将详细阐述!