.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的基本框架的朋友。謝謝
相關文章
相關標籤/搜索