程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF分布式開發步步為贏(11):WCF流處理(Streaming)機制

WCF分布式開發步步為贏(11):WCF流處理(Streaming)機制

編輯:關於.NET

WSE3.0框架提供了數據優化傳輸機制,WSE3.0構建Web服務安全(4):MTOM消息傳輸優化和文件上傳、下載疑問裡進行了介紹。WCF同樣也提供了流操作來支持大數據對象的傳輸和處理優化機制,今天我們WCF分布式開發步步為贏系列的(4):使用流操作(Streaming Operations)優化傳輸。本節會詳細介紹流操作的相關概念、編程實現過程,以及實際開發過程中需要主要的一些問題。本節結構:【1】流處理的概念【2】流處理的特點【3】示例代碼分析【4】總結。最後上傳本文的示例代碼。

Streaming,本文翻譯為流處理(張逸兄翻譯的Programming WCF Services一書裡把這個機制翻譯為“流操作”,不存在爭議。我選擇“流處理”一詞的意思,只是想把這個Streaming詞形象准確化,動名詞,流化處理、流處理,翻譯為流操作,初學者會誤會認為這個是一個服務操作。因為Streaming只是WCF內建的一個機制。而不是操作。)

我們首先來理解什麼是Streaming流處理。

【1】Streaming流處理的概念:

通常情況,客戶端和服務端進行交互,傳遞消息,都是放到接收端的緩存裡,待接收完畢後再進行處理。無論接收端是客戶端還是服務端都是如此。

【1.1】要解決的問題:

當客戶端調用服務時,要阻塞客戶單進程,直到消息發送完畢,服務端才開始處理數據,然後是返回處理完畢的結果給客戶端,客戶端接收完畢,才能解除阻塞。這樣帶來的問題是當消息傳遞的時間很短,相對處理時間可以忽略不計,不會影響系統服務的效率。但是要是消息數據很大,比如是圖片或者多媒體對象。每次傳輸時間相對較大,這樣接收端的等待時間過久,勢必每次阻塞都會很長,進程無法繼續執行。因而導致效率低下。

【1.2】Streaming流處理:

Streaming流處理就是WCF提供的主要針對大量消息數據處理的一種優化機制。WCF允許接收端通過通道接受消息的同時,啟動對消息數據的處理,這樣的過程稱為流傳輸模型。

【2】Streaming流處理的特點:

顯然對於處理大量的消息數據而言,流處理機制改善了系統的吞吐量和響應效率。

【2.1】流處理操作定義:

WCF的流處理機制需要使用.NET FrameWork定義的Stream類(它是FileStream, NetworkStream, MemoryStream 的父類)。流處理適用一下場景:

[ServiceContract]
interface IMyContract
{
    [OperationContract]
    Stream StreamReply1( );

    [OperationContract]
    void StreamReply2(out Stream stream);

    [OperationContract]
    void StreamRequest(Stream stream);

    [OperationContract(IsOneWay = true)]
    void OneWayStream(Stream stream);
}

它可以做為返回數據、參數、輸出參數的類型。當然也可以作為單調服務的操作參數。這裡使用的參數必須是可序列化的,例如MemoryStream。而FileStream不支持序列化因而不能作為參數或者返回數據的類型。

【2.2】流處理與綁定協議:

流處理機制在特定的綁定協議中才能使用,目前是BasicHttpBinding, NetTcpBinding, 和NetNamedPipeBinding 支持流處理模型。但是在默認情況下,WCF禁止流處理模式。

流傳輸模式使用使用TransferMode進行配置,TransferMode為枚舉類型,其定義如下:

public enum TransferMode
     {
         // Summary:
         //     The request and response messages are both buffered.
         Buffered = 0,
         //
         // Summary:
         //     The request and response messages are both streamed.
         Streamed = 1,
         //
         // Summary:
         //     The request message is streamed and the response message is buffered.
         StreamedRequest = 2,
         //
         // Summary:
         //     The request message is buffered and the response message is streamed.
         StreamedResponse = 3,
     }

只有Streamed模式支持2.1中列舉的流處理模式場景。除了直接在服務上配置屬性以外,我們還可以再服務的配置文件裡定義流傳輸模式。代碼如下:

<basicHttpBinding>
         <binding name="basicHttpBinding" receiveTimeout="10:10:10"  transferMode="Streamed" maxReceivedMessageSize="200000">
         </binding>
       </basicHttpBinding>
       <netTcpBinding>
         <binding name="netTcpBinding" receiveTimeout="10:10:10" transferMode="Streamed" maxReceivedMessageSize="200000">
         </binding>
       </netTcpBinding>

此為托管宿主的配置文件,特定的綁定協議,可以配置其傳輸模式。

【2.3】注意:

流處理在使用http協議時,其默認消息長度是64K,如果希望增加數據長度,需要在配置文件裡重新設置。如: maxReceivedMessageSize="200000",具體代碼如下:

<basicHttpBinding>
         <binding name="basicHttpBinding" receiveTimeout="10:10:10" transferMode="Streamed" maxReceivedMessageSize="200000">
         </binding>
</basicHttpBinding>

【3】示例代碼分析:

這裡測試的流處理機制,使用的是處理圖片的上傳於下載,分別使用Stream和其子類MemoryStream作為參數或者返回消息數據的類型。基本代碼演示的是流處理三種模式場景:

【3.1】服務端:

服務契約分別定義了下載數據和上傳數據,下載數據使用的類型MemoryStream,上傳數據參數類型是是Stream。具體代碼如下:

//1.服務契約
     [ServiceContract( Namespace = "http://www.cnblogs.com/frank_xl/")]
     public interface IWCFService
     {
         //操作契約,獲取數據流
         [OperationContract]
         MemoryStream DownLoadStreamData(string fileName);

         //操作契約,輸出數據流
         [OperationContract]
         void DownLoadStreamDataOut(out MemoryStream stream, string fileName);

         //操作契約,上載數據流,單向操作的消息轉換為數據流
         [OperationContract(IsOneWay=true)]
         void UpLoadStreamData(Stream stream);
     }
     //2.服務類,繼承接口。實現服務契約定義的操作
     public class WCFService : IWCFService
     {
         //1實現接口定義的方法,下載文件數據流
         public MemoryStream DownLoadStreamData(string fileName)
         {
            // Stream stream = 
             byte[] file = new byte[200000];
             String filePath = AppDomain.CurrentDomain.BaseDirectory + @"\" + fileName;
             file = File.ReadAllBytes(filePath);
             MemoryStream memoryStream = new MemoryStream(file);
             return memoryStream;
         }
         //2實現接口定義的方法,下載文件數據流
         public void DownLoadStreamDataOut(out MemoryStream stream, string fileName)
         {
             // Stream stream = 
             byte[] file = new byte[200000];
             String filePath = AppDomain.CurrentDomain.BaseDirectory + @"\" + fileName;
             file = File.ReadAllBytes(filePath);
             MemoryStream memoryStream = new MemoryStream(file);
             stream = memoryStream;

         }
         //3實現接口定義的方法,上傳文件數據流
         public void UpLoadStreamData(Stream stream)
         {
             // codes here to deal with the stream Stream stream = 
             Console.WriteLine("The Stream length is {0}",stream.Length);

         }
     }

【3.2】托管宿主:

我們分別使用basicHttpBinding和netTcpBinding定義了兩個服務終結點,這裡不要忘記設置最大接受消息數據大小maxReceivedMessageSize="200000",如果設置較小會導致接受數據超過設定的錯誤。具體代碼如下:

<system.serviceModel>
     <services>
       <service behaviorConfiguration="WCFService.WCFServiceBehavior"
         name="WCFService.WCFService">
         <endpoint
           address="http://localhost:8002/WCFService"
           binding="basicHttpBinding"
           contract="WCFService.IWCFService">
         </endpoint>
         <endpoint
          address="net.tcp://localhost:8004/WCFService"
          binding="netTcpBinding"
          contract="WCFService.IWCFService">
         </endpoint>
         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
         <endpoint address="mex"  binding="mexTcpBinding" contract="IMetadataExchange" />
         <host>
           <baseAddresses>
             <add baseAddress="http://localhost:8001/"/>
             <add baseAddress="net.tcp://localhost:8003/"/>
           </baseAddresses>
         </host>
       </service>
     </services>
     <behaviors>
       <serviceBehaviors>
         <behavior name="WCFService.WCFServiceBehavior">
           <serviceMetadata httpGetEnabled="true" />
           <serviceDebug includeExceptionDetailInFaults="false" />
         </behavior>
       </serviceBehaviors>
     </behaviors>
     <bindings>
       <basicHttpBinding>
         <binding name="basicHttpBinding" receiveTimeout="10:10:10" transferMode="Streamed" maxReceivedMessageSize="200000">
         </binding>
       </basicHttpBinding>
       <netTcpBinding>
         <binding name="netTcpBinding" receiveTimeout="10:10:10" transferMode="Streamed" maxReceivedMessageSize="200000">
         </binding>
       </netTcpBinding>
     </bindings>
   </system.serviceModel>

【3.3】客戶端:

客戶端分別測試數據的上傳和下載,使用不同的方法。這裡的測試目前

【4】總結:

本文介紹了WCF流處理模型,但是實現代碼出現問題。

(1)作為WCF的流處理機制,確實為我們的大規模消息數據傳輸提供了理想的機制,提高了系統的效率和響應速度。

(2)Stream作為.net類庫的內部類型,在.net平台上使用來說較為方便,但是與異構平台的交互勢必受到諸多限制,也違背了WCF跨平台的初衷。

(3) 我在調試這個示例代碼的過程中遇到了幾個錯誤,基本都整理出來放到WCF分布式開發常見錯誤裡了。使用netTcpBinding綁定進行數據傳輸的時候,一個很有價值的錯誤就是:the socket connection was aborted. this could be caused by an error processing your message or a receive timeout being exceeded by the remote host ...這個錯誤我google國內和國外的一些資料,但是解決的辦法都是更換協議。其實是一種很無奈的措施,目前我還沒有找出更好的解決辦法就是基於netTcpBinding。表面的原因是服務處理超時。但是具體的錯誤信息沒有這樣簡單。我更換協議以後其他的流服務操作調用出了問題。所以這個只能針對特定的操作有幫助。我把這個錯誤收集起來供大家參考。也希望發揮大家的作用把這個問題解決。

也許這個錯誤應該反映給WCF的開發小組,無論國內還是國外的技術論壇,包括MSDN都有人遇到這樣的問題,而沒有一個最佳的解決方案。這裡我對流處理示例代碼分別打包,目前都有問題。

<1>流處理機制示例1裡代碼測試上傳文件,成功,下載文件錯誤。

http://files.cnblogs.com/frank_xl/WCFServiceStreamingFrankXuLei.rar

<2>這裡使用的是字節數組,測試下載文件,下載文件是成功的,上傳文件失敗。

http://files.cnblogs.com/frank_xl/WCFServiceStreamingByteArrayFrankXuLei.rar

兩個失敗的原因都是一樣,套接字中斷,連接超時。WCF分布式開發步步為贏(10):請求應答(Request-Reply)、單向操作(One-Way)、回調操作(Call Back).,我進行了整理,也查找了國外的論壇,沒有找到理想的解決辦法。我已經嘗試了修改接受時間的限制,但是不起作用。我會繼續關注這個問題,也希望有興趣的朋友補充。MSDN論壇上有人提供了解決的方法,但是不理想,更換協議。希望微軟WCF的開發、測試小組早日注意這個問題。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved