在本人的“.NET简谈组件程序设计之(初识远程调用) ”一文中,我们了解到什么是远程调用或者说在.NET平台上远程调用是什么样子的,可能和偏低层(Socket\Rpc)的远程调用有点距离。这只是系统为我们封装了假象而已,看不见不代表没有这逻辑,是为我们减轻了劳动负担。[王清培版权所有,转载请给出署名]
这篇文章我们来简单的了解一下在.NET平台上有一个强有力的远程调用武器,也是上一篇文章中我一笔带过的远程英雄.NetRemoting。
其实在.NET平台里面到处都能看见Remoting的影子,只不过我们平时都很少有机会与它接触,因为它通常工作于“后端”,躲在界面显示技术(如:Winform\Asp.net\Wpf.)
界面显示层是将信息以友好的方式展现在用户面前,但是真正的英雄通常都在背后默默的支持它,以更华丽的效果展现。(如:Thread\WebService\Remoting\Wcf...)。
其实在我们不断学习的过程中会慢慢的在我们脑海里浮现出我们所学习的东西的模型,比如我们是专研.NET这门技术,那么在我们脑子里是否已经有了一个简单而模糊的阴影,能看见这种阴影才证明我们刚刚入门。如果未曾有这种感觉,那么我们对他还是一无所知,所谓知己知彼方能百战百胜,说明我们还未入门。因为精通都是从模糊开始的,没有人一跃而过。(这只是本人对学习过程中的一点小小的感悟)
那么.NetRemoting是何许人也,它是什么?一般在哪里才能看见它?这篇文章就是来介绍这位大人物的。[王清培版权所有,转载请给出署名]
定义:.NetRemoting是.NET平台里面一个专门用来处理远程调用的框架,是已经为我们做好的、现成的框架,我们可以利用他来进行远程调用。
上面是我对他的一个简单的定义吧。上篇文章我简单的介绍了什么是远程调用,在.NET里面只要是跨AppDomain(应用程序域)的都属于远程调用,因为.NET在我们物理宿主进程里面又抽象了一个他自有的逻辑宿主。在操作系统看来,AppDomain是不存在的,但是在CLR看来它是存在的,我们的程序要想跑起来必须进过CLR的一系列的逻辑部署,也就是构造这么一个逻辑空间。[详情请看本人的“.NET简谈组件程序设计之(AppDomain应用程序域) ”一文
.NetRemoting基本结构
那么既然是框架它就肯定有一个结构,也就是他的工作原理。
在Remoting没有出来之前,如果不进过一番复杂的编写,我想夸AppDomain调用可能只局限于统一进程内了。(这句话可能会引起误会,我是说在.NET现有的框架基础上而言。)
然而有了Remoting之后,一切变的简单多了,我们只需要了解简单的网络原理、套接字原理、协议等等就能很好的配置这个框架,以进行远程调用。它将远程调用延伸到了任何地方,不只是在同一进程内了。
原有的同一进程内的远程调用框架没有变,Remoting只是添加了点东西以支持夸进程夸网络。(比如:RefObjet对象\RealProxy对象)。
之前我说过Remoting是一个高扩展性的框架,从上图中我们可以看出它的基本结构是很清晰的、很模块化。都是通过接口关联,只要我们熟悉了之后就能切入自己的逻辑。[王清培版权所有,转载请给出署名]
.NetRemoting示例
在.NET里面不管是夸进程还是夸机器之间的AppDomain调用都是通过远程调用技术进行处理的。在同一个进程里面可能不会涉及到物理上的通讯,直接拿到代理就OK了,只是一些逻辑宿主之间的处理。
那么我们来看一个简单的示例:
1:对照上图,最下面的是关于通讯的端点,那么我们首先需要设置一个能够进行远程通讯的地址,在Remoting里面就是Channel(信道),消息从信道出去流线服务器端的信道。
在Remoting里面系统提供给了我们三种类型的信道,分别是Ipc\Tcp\Http。Ipc:是进程间调用用的,Tcp:是用TCP的协议来处理通讯,HTTP:是用HTTP协议来处理通讯。我们根据项目的需要可以进行设置。
代码注册信道:
IDictionary dipropertis = new Hashtable(); dipropertis["name"] = "Myserverchannel";//信道名称 dipropertis["port"] = 8005;//端口 IChannel tcpchannel = new TcpChannel(dipropertis, null, binaryformatter);//TCP信道 ChannelServices.RegisterChannel(tcpchannel); IChannel httpchannel = new HttpChannel(8006);//HTTP ChannelServices.RegisterChannel(httpchannel); IChannel ipcchannel = new IpcChannel("myport");//IPC进程间通讯 ChannelServices.RegisterChannel(ipcchannel);
所有的通道Channel都是来自IChannel接口,所以我们可以定义自己的一些通讯实现。
上图代码中我分别注册了三种类型的通道,通道也就是通讯的过程。对于IPC类型的通道我们只需要提供一个管道名称就行了。如果我们使用默认的Channel构造函数,只需要提供端口就行了,但是如果要设置信道名称就需要用字典的方式进行多属性的设置,因为没有提供这方面的构造函数重载。在我们注册第一个TCP通道的时候,我定义了一个键值对的Hashtable,键name的代表信道名称,port代表端口。
上述代码看来,通道就是具体通讯的细节,终结点在哪里?使用的消息是什么?这样就能完好的把消息送到网络的另一端。进程间通讯IPC是通过管道的机制实现的,所以不涉及端口、网络。
代码注册消息格式化器:
通道是位于Remoting整体框架的最末端,底层通讯的细节。在这上面一层是消息格式化器,也就是对象的序列化过程,在对象的持久化状态和托管内存状态之间转换。
我们来看一下怎么在服务端注册消息格式化器的:
//注册信道 BinaryServerFormatterSinkProvider binaryformatter = new BinaryServerFormatterSinkProvider();//信道消息处理程序 binaryformatter.TypeFilterLevel = TypeFilterLevel.Full;//完全序列化级别 SoapServerFormatterSinkProvider soapformatter = new SoapServerFormatterSinkProvider(); soapformatter.TypeFilterLevel = TypeFilterLevel.Full;
系统也我们实现了两种类型的对象格式化方式,二进制、SOAP。
对象的TypeFilterLevel属性是设置格式化器的级别,由于系统默认的序列化级别只能序列化简单的托管类型,如果要想序列化复杂而危险的对象我们需要设置该枚举值。
在注册通道的时候可以将格式化器的实例带进去,好让通道知道它的消息如何被格式化。
代码注册服务类型:
在往上走就到代理的模块,代理在这篇文章中我就不扯了,对于这篇文章它不是重点。代理在我们日常开发中不太会去深入的去研究它,比较复杂,基本上被隐藏了。我们只需要理解它就行了。有兴趣的可以查看相关资料。
我们来看一下最上层的代码:
//注册类型 RemotingConfiguration.RegisterWellKnownServiceType(typeof(MyClassLibrary.Class1), "Class1", WellKnownObjectMode.SingleCall); //客户端激活模式 RemotingConfiguration.RegisterActivatedServiceType(typeof(MyClassLibrary.Class2));
服务器端要想提供服务,就需要将提供服务的对象进行注册。好让服务器知道提供了那些服务。
RemotingConfiguration对象提供了很多静态方法,我们可以通过RegisterWellKnownServiceType方法注册服务器端激活模式,或者通过RegisterActivatedServiceType方法注册客户端激活模式。这两种激活模式的差别在后续的文章中讲会讲解到。[王清培版权所有,转载请给出署名]
客户端代码:
我们看一下客户端该做些什么:
string uri = "tcp://localhost:8005"; RemotingConfiguration.RegisterActivatedClientType(typeof(MyClassLibrary.Class2), uri); RemotingConfiguration.RegisterWellKnownClientType(typeof(MyClassLibrary.Class1), uri + "/Class1");
客户端只需要通过RemotingConfiguration中的关于客户端注册的方法注册远程服务的类型,当我们在实例化对象的时候Remoting会自动的帮我们进行远程处理。
结:这篇文章只是粗略讲解一下Remoting的结构。下一篇文章我们将更深入一点的了解Remoting,包括激活模式、管理配置等。