代码之家  ›  专栏  ›  技术社区  ›  Francesco De Vittori

WCF HttpTransport:流式传输与缓冲传输模式

  •  19
  • Francesco De Vittori  · 技术社区  · 15 年前

    HttpTransport -基于自定义绑定。绑定使用自定义 MessageEncoder 那差不多是 BinaryMessageEncoder

    Silverlight和Windows客户端使用web服务。

    问题

    var transport = new HttpTransportBindingElement(); // quotas omitted for simplicity
    var binaryEncoder = new BinaryMessageEncodingBindingElement(); // Readerquotas omitted for simplicity
    var customBinding = new CustomBinding(new GZipMessageEncodingBindingElement(binaryEncoder), transport);
    

    然后我做了一个实验:我改变了 TransferMode Buffered StreamedResponse

    var transport = new HttpTransportBindingElement()
    {
        TransferMode = TransferMode.StreamedResponse // <-- this is the only change
    };
    var binaryEncoder = new BinaryMessageEncodingBindingElement(); // Readerquotas omitted for simplicity
    var customBinding = new CustomBinding(new GZipMessageEncodingBindingElement(binaryEncoder), transport);
    

    神奇的是,不再有内存异常 . 对于小消息,该服务稍慢一些,但随着消息大小的增长,差异越来越小。

    问题解决了,但是:我无法解释这里发生了什么。我的惊讶源于 我没有以任何方式改变合同 . 一、 我没有和一个 Stream 参数等,通常用于流式消息。我仍然使用具有相同DataContract和DataMember属性的复杂类。 我刚修改了端点

    我以为设置传输模式只是 使可能 有谁能解释一下当你改变的时候在引擎盖下到底发生了什么 ?

    4 回复  |  直到 15 年前
        1
  •  20
  •   Community Mohan Dere    9 年前

    当您使用“gzimpessageencodingbindingelement”时,我假设您使用的是MS GZIP示例。

    看一看 DecompressBuffer() 在gzimpessageencoderfactory.cs中,您将了解缓冲模式下的情况。

    DecompressBuffer将接收(1)的“ArraySegment buffer”参数 25米 大小。然后,该方法将创建一个MemoryStream,使用(2)将缓冲区解压缩到其中 . 然后它将执行MemoryStream.ToArray(),将内存流缓冲区复制到新的(3) 50米 50米+ ,实际上,它可能要大得多-在我的情况下,50米阵列的距离总是67米。

    在DecompressBuffer结束时,(1)将被返回到BufferManager(它似乎永远不会被WCF清除),(2)和(3)受GC(它是异步的,如果您比GC快,那么您可能会得到OOM异常,即使清除后会有足够的mem)。(4) 可能会返回到BinaryMessageEncodingBindingElement.ReadMessage()中的BufferManager。

    25+50+50+例如65=190M 从未 要清理,除非手动调用BufferManager.Clear(),而且我不知道如何处理WCF使用的缓冲区管理器,请参见以下问题: How can I prevent BufferManager / PooledBufferManager in my WCF client app from wasting memory? ]

    更新: wcf conditional compression ) 内存消耗、cpu负载和启动时间减少 (没有现成的数字)然后从缓冲传输模式迁移到流传输模式( How can I prevent BufferManager / PooledBufferManager in my WCF client app from wasting memory? ) !

        2
  •  12
  •   Bryan Denny    15 年前

    基本上,如果你不设置 TransferMode 若要流式传输,则默认为“缓冲”。所以如果你要发送大量的数据,它会在你的内存端建立数据,然后在所有数据加载并准备好发送后发送。这就是为什么出现内存不足错误的原因,因为数据非常大,超过了机器的内存。

    但这并不意味着也必须为流媒体设置接收器。它们可以设置为缓冲区,如果它们没有足够的内存存储您的数据,则会遇到与发送方相同的问题。

    为了获得最佳结果,两个端点都应该设置为处理流(对于大型数据文件)。

    MessageContracts 而不是 DataContracts

    请参阅以下MSDN文章 MessageContracts Datacontracts 更多信息。这里有更多关于 Buffered vs Streamed

        3
  •  1
  •   Arashv    12 年前

    我认为(我可能错了),限制用户使用 Stream Streamed

    至于您的另一个问题,如果没有看到完整的代码,很难判断实际发生了什么,但我认为通过使用gzip,您实际上是将所有消息数据压缩为一个字节数组,将其交给WCF,在客户端,当客户端请求SOAP消息时,底层通道打开一个流以读取消息,而WCF通道用于流式传输,启动流式数据,因为它是消息的主体。

    无论如何,你应该注意设置 MessageBodyMember

        4
  •  0
  •   arghtype Castaldi    10 年前

    缓冲: 在上传/下载之前,它需要将整个文件放入内存。

    流媒体: 文件可以分块传输。