zoukankan      html  css  js  c++  java
  • WCF流处理(Streaming)机制(转)

    我们首先来理解什么是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都有人遇到这样的问题,而没有一个最佳的解决方案。这里我对流处理示例代码分别打包,目前都有问题。

    http://blog.csdn.net/book_frank_xl/article/details/4735907
  • 相关阅读:
    PAT1118:Birds in Forest
    PAT1112:Stucked Keyboard
    PAT1091:Acute Stroke
    Java基础006 --- 类、接口、对象
    Java基础005 --- 安全管理器、可变参数等
    Java基础004 --- BigInteger和BigDecimal
    Java基础003 --- 原始数据类型
    maven完整学习笔记(2)--- 依赖范围和依赖传递
    maven完整学习笔记(1)--- 基本概念及基础命令
    Java编译器007---javac 其它选项
  • 原文地址:https://www.cnblogs.com/quietwalk/p/2133221.html
Copyright © 2011-2022 走看看