zoukankan      html  css  js  c++  java
  • WCF分布式开发步步为赢(11):WCF流处理(Streaming)机制

    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类(它是FileStreamNetworkStreamMemoryStream 的父类)。流处理适用一下场景:

    复制代码
    [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】流处理与绑定协议:

        流处理机制在特定的绑定协议中才能使用,目前是BasicHttpBindingNetTcpBinding, 和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里代码测试上传文件,成功,下载文件错误。

    /Files/frank_xl/WCFServiceStreamingFrankXuLei.rar

    <2>这里使用的是字节数组,测试下载文件,下载文件是成功的,上传文件失败。/Files/frank_xl/WCFServiceStreamingByteArrayFrankXuLei.rar

     两个失败的原因都是一样,套接字中断,连接超时。WCF分布式开发常见错误解决(10):套接字连接中断,The socket connection was aborted ,我进行了整理,也查找了国外的论坛,没有找到理想的解决办法。我已经尝试了修改接受时间的限制,但是不起作用。我会继续关注这个问题,也希望有兴趣的朋友补充。MSDN论坛上有人提供了解决的方法,但是不理想,更换协议。希望微软WCF的开发、测试小组早日注意这个问题。

    <3>Streaming代码修改完毕,测试成功,请大家下载新的文件参考:/Files/frank_xl/WCFServiceStreamingSuccefullyFrankXuLei.rar 
      以前代码因为配置错误,绑定的配置没应用对。我今天修改完毕。
     参考文章:

    1.《Programming WCF Services》;

    2.WSE3.0构建Web服务安全(4):MTOM消息传输优化和文件上传、下载

  • 相关阅读:
    HDU 5912 Fraction (模拟)
    CodeForces 722C Destroying Array (并查集)
    CodeForces 722B Verse Pattern (水题)
    CodeForces 722A Broken Clock (水题)
    CodeForces 723D Lakes in Berland (dfs搜索)
    CodeForces 723C Polycarp at the Radio (题意题+暴力)
    CodeForces 723B Text Document Analysis (水题模拟)
    CodeForces 723A The New Year: Meeting Friends (水题)
    hdu 1258
    hdu 2266 dfs+1258
  • 原文地址:https://www.cnblogs.com/GoogleGetZ/p/5752576.html
Copyright © 2011-2022 走看看