.NET简谈组件程序设计之(详解NetRemoting结构)

在本人的上一篇文章中只是简单的介绍了一下.NETRemoting的通常概念和基本的使用。这篇文章我想经过本身的学习和理解将对.NETRemoting的总体的一个框架进行通俗的讲解,其中最重要的就是信道(管道)处理模型思想,这里面蕴含了不少的设计原理。 [王清培版权全部,转载请给出署名]
.NETRemoting远程处理架构是一个半成品,是.NET给咱们的扩展框架,要想用于商业项目必须进行一些安全、性能方面的控制。要想进行必定深度的扩展那就要必须了解它的总体结构,各个点之间的关系才能很好的控制它。
网上讲解.NETRemoting的文章不少,可是通俗易懂的没有几篇,都是大概讲解了一下总体模型或者从MSDN上COPY过来,未能对各模型之间的接口作详细讲解。了解.NETRemoting的朋友都知道,它的实现基本上都是经过接口与接口之间的串联造成处理管道,这也让咱们想起来了设计模式中首要说起的面向对象设计思想“面向接口编程”。
本人在学习.NETRemoting的时候仍是比较痛苦的,因为中文资料缺少只能经过搜索网上零零散散的知识点再经过拼命的理解、换位思考、提升抽象层次,才终于参透为何那么多接口之间的关系,在这里小弟会一一讲解那些诸如IClientChannelSink、IClientChannelSinkProvider、IMessageSink等等接口究竟是什么意思,提供程序与信道接收器之间又是啥关系,在信道处理模型中是怎么利用多态来设计的。

.NETRemoting处理管道
在.NETRemoting中它的总体处理模型有点像ASP.NET中的HTTP处理管道模型,消息从最上面的入口进入而后一个一个的传递到各个处理模块中,这样就造成了一个抽象的处理管道。
图1(客户端信道处理):
 
这是客户端信道处理模型的大概结构。任何客户端对跨远程处理都是经过代理进行的,代理分为两部分一种是透明代理,一种是真实代理;
透明代理是经过真实代理动态生成的,透明代理的全部成员都是客户端将要调用的远程对象的一个虚拟镜像。为何要说是虚拟的,是由于透明代理只是方便客户端调用的,当咱们NEW一个远程对象时,系统将为咱们动态的生成一个继承自你NEW的那个对象的代码,而后动态生成内存透明代理对象。
透明代理包括了对真实代理的调用,真正的幕后主脑是RealProxy对象,它包括了对信道处理结构的引用。在上面的图1中为何真实代理是用IMessageSink接口来启动整个信道处理模型的。这里也是最为难理解的入口点,下面咱们将本身的抽象能力提高一个层次才能知道系统为何要这样设计。 [王清培版权全部,转载请给出署名]
图2(服务器端信道处理):
.NETRemoting饶人的名词解释
不论是服务器端仍是客户端都是经过信道处理模型来对双方的消息进行一系列的处理。客户端的信道处理和服务器端的信道处理有点区别,这些区别是来自它们的更高层次的抽象。这句话可能根本很差理解,从我上面的两幅图中我想读者多多少少能理解点意思来,在信道处理管道中都是经过每一个信道接收器提供程序来建立有处理能的信道接收器。
咱们先来解决一些会给咱们理解带来困扰的英文单词:
Channel:在系统中它表示信道,也就是处理管道。
IChannel:表示一个抽象的处理管理,用来标识一个管道的信息,如管道名称,管道级别之类的。
Sink:接收器,也就是管道中的消息处理环节,系统一般用这个单词来组合,也会让初学者容易参数混淆(看过这篇文章后你就不会在混淆了)。
Provider:通常表示为提供程序,在.NETRemoting里面的提供程序这是某些环境的一个入口点,好比在系统中序列化环节,系统经过SoapClientFormatterSinkProvider提供程序来建立SoapClientFormatterSink信道接收器,这里的提供程序是表示即将进入处理过程,这个处理过程表示某一个处理环节,在这个处理环节中可能包括不少用来接收要处理的信息,全部叫作信息接收器,也就是sink结尾的接口。
IClientChannelSinkProvider:客户端信道接收器提供程序,也就是图1中表示的每一个对消息的处理环节部分。该接口有一个NEXT属性用来链接下一个提供程序,这样就串联起一个抽象的处理管道。咱们要记住提供程序这是建立处理环节的入口点,真正用来处理消息的是sink结尾的接口,这里也就是IClientChannelSInk对象。
IClientChannelSink:客户端消息接收器,用于在管道处理中对消息的传递进行个性化修改,咱们能够在这个里面进行一些消息传递的压缩、编码等等。
IServerChannelSinkProvider:服务器端信道接收器提供程序,和客户端是相同的功能,都是用来建立信息接收器用的,只不过这里是服务器端的信息处理。
IServerChannelSink:服务器端消息接收器,用来在服务器端进行消息的处理,能够对传输过来的消息进行解压缩、反编码等等,与客户端功能是对应的。
IMessageSink:入门的朋友可能会对这个接口参数误解,这是啥接口啊?我不是有了Sink类型的接口了吗?为何还要消息接口?其实这里也很好理解,为何须要各类各样的接口,这就是我上面所说的“将本身的抽象能力提高一个高度”才能理解。若是对接口编程不是很熟悉的朋友多是不太好理解。每种接口表示某种抽象,我打个比方,若是有一个对象它既实现了IMan接口,又实现了IDog接口,它在与人交流的时候咱们知道它是实现了人类接口的对象,因此咱们认识它而且能与它进行交流,若是它与狗交流的话那么狗狗也是认识它的由于它也实现了狗的接口。从这里讲,实现多个接口的对象具备很深的抽象层次,在某些场合它被视为一种类型,在另一些场合它又被视为另外一种类型。下面咱们讲到具体的接口实现时,就明白我所说的意思了。
.NETRemoting信道接收器
上面的名词解释的差很少了,咱们来动动手吧;
按照上面的客户端信道模型图,咱们先来实现一个IClientChannelSinkProvider接口,咱们将利用这个接口来建立一个能处理消息的IClientChannelSink接口。
using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Lifetime;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Ipc;

namespace MyClassLibrary.CustomProvider
{
         public class ClientCustomProvider : IClientChannelSinkProvider
        {
IClientChannelSinkProvider 成员 #region IClientChannelSinkProvider 成员
                 /// <summary>
                 /// 建立该提供程序的信道接收器,全部的信道接收器提供程序均要实现CreateSink方法,保证全部的信道接收器能串联起来。
                 /// </summary>
                 /// <param name="channel">上下文发送接口</param>
                 /// <param name="url">对象的终结点</param>
                 /// <param name="remoteChannelData">信道数据</param>
                 /// <returns>IClientChannelSink客户端信道接收器接口</returns>
                 public IClientChannelSink CreateSink(IChannelSender channel, string url, object remoteChannelData)
                {
                         return new ClientCustomSink(Next.CreateSink(channel, url, remoteChannelData));
                }
                 /// <summary>
                 /// 获取下一个信道接收器提供程序。经过这里的NEXT属性将全部的信道接收器链接起来。
                 /// </summary>
                 public IClientChannelSinkProvider Next { get; set; }

                #endregion
        }
}
这里是咱们建立客户端接收器提供程序的代码,在这里咱们建立个一个ClientCustomSink信道接收器对象,可是在构造函数中咱们用NEXT属性又建立了一个信道接收器做为参数传入到对象,这样作的目的就是能保证每个消息接收器处理完成后能接着传递给下一个信息接收器处理。
using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Lifetime;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Ipc;

namespace MyClassLibrary.CustomProvider
{
         public class ClientCustomSink : BaseChannelSinkWithProperties, IClientChannelSink
        {
                IClientChannelSink nextchannelsink;
                 public ClientCustomSink(IClientChannelSink nextchannel)
                {
                        nextchannelsink = nextchannel;
                }
IClientChannelSink 成员 #region IClientChannelSink 成员

                 public void AsyncProce***equest(IClientChannelSinkStack sinkStack, IMessage msg, ITransportHeaders headers, System.IO.Stream stream)
                {
                        nextchannelsink.AsyncProce***equest(sinkStack, msg, headers, stream);
                }

                 public void AsyncProce***esponse(IClientResponseChannelSinkStack sinkStack, object state, ITransportHeaders headers, System.IO.Stream stream)
                {
                        nextchannelsink.AsyncProce***esponse(sinkStack, state, headers, stream);
                }

                 public System.IO.Stream GetRequestStream(IMessage msg, ITransportHeaders headers)
                {
                        msg.Properties.Add( "自定义消息", "自定义消息值");
                         return nextchannelsink.GetRequestStream(msg, headers);
                }

                 public IClientChannelSink NextChannelSink
                {
                        get { return nextchannelsink; }
                }

                 public void ProcessMessage(IMessage msg, ITransportHeaders requestHeaders, System.IO.Stream requestStream, out ITransportHeaders responseHeaders, out System.IO.Stream responseStream)
                {
                        nextchannelsink.ProcessMessage(msg, requestHeaders, requestStream, out responseHeaders, out responseStream);
                }
                 public IDictionary NextProperise
                {
                        get { return nextchannelsink.Properties; }
                }
                #endregion
        }
}
有一这里的代码太长我就不加注释了。这个对象主要实现了IClientChannelSink接口,也就是信道接收器接口,在这个接口面明前比Provider提供程序多了不少东西。这里才是真正处理的地方,系统为了代码的整洁性将提供程序与信息接收器分离开,其实也能够将这两个接口进行合并。在构造函数里面咱们用一个私有的IClientChannelSink保存了下一个Sink。该对象还实现了BaseChannelSinkWithProperties抽象类,这个类是用来获取下一个信道接收器的内部属性用的。若是咱们没有实现这个抽象类就要本身实现NextProperise属性。 [王清培版权全部,转载请给出署名]
其实在IClientChannelSink里面比较重要的就是GetRequestStream和ProcessMessage两个方法,一个是用来获取即将要发送的Stream流,一个是进行发送的方法。为了便于你们的理解,请看图3:
我上面的处理流程不必定就是GetRequestStream是第一步,可是它是ProcessMessage方法的上一步,因此我用一、2表示。当GetRequestStream到了最后一个Sink时,系统将进行最后的调用,也就是进行远程发送了。
在GetRequestStream中咱们加入了一些本身定义的数据,咱们在经过服务器端的IServerChannelSink获取这消息。
using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Lifetime;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Ipc;

namespace MyClassLibrary.CustomProvider
{
         public class ServerCustomSink : BaseChannelSinkWithProperties, IServerChannelSink
        {
                 private IServerChannelSink iserverchannelsink;
                 public ServerCustomSink(IServerChannelSink serverchannel)
                {
                        iserverchannelsink = serverchannel;
                }
IServerChannelSink 成员 #region IServerChannelSink 成员

                 public void AsyncProce***esponse(IServerResponseChannelSinkStack sinkStack, object state, IMessage msg, ITransportHeaders headers, System.IO.Stream stream)
                {
                         if (iserverchannelsink != null)
                                iserverchannelsink.AsyncProce***esponse(sinkStack, state, msg, headers, stream);
                         throw new NotImplementedException();
                }

                 public System.IO.Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, object state, IMessage msg, ITransportHeaders headers)
                {
                         if (iserverchannelsink != null)
                                iserverchannelsink.GetResponseStream(sinkStack, state, msg, headers);
                         throw new NotImplementedException();
                }

                 public IServerChannelSink NextChannelSink
                {
                        get { return iserverchannelsink; }
                }

                 public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders,
                        System.IO.Stream requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out System.IO.Stream responseStream)
                {
                        sinkStack.Push( this, "ok");
                         return NextChannelSink.ProcessMessage(sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream);
                }

                #endregion

        }
}
图4:
总结:
.NETRemoting是一个很是成熟的CLR远程处理框架,其实现的原理也很复杂,基本上每一部分均可以扩展,它的内部实现都是经过面向接口来的,接口的粒度也很是小。从IXXXChannelSinkProvider和IXXXChannelSink两种接口就能够看出来,里面的空间很大。
本篇文章只是本人在学习.NETRemoting过程当中的一点小小的感悟献给那些尚未搞清楚Remoting的基本框架的朋友。谢谢
相关文章
相关标签/搜索