如何在不将流读取到结尾的情况下中止WCF服务中的流?

17

这是我在上周一直在调查但找不到解决方案的问题。发现有人问过相同的问题,但从未得到答案,希望这也能帮助其他人。

我有一个返回包含流的对象的WCF服务。我使用带有流传输和Mtom的basicHttpBinding将其发送到客户端。

客户端调用WCF服务,并在接收响应对象后立即关闭代理。

接下来,客户端读取从WCF服务获取的流,并将其写入本地磁盘上的文件。所有这些都很好地工作。

我的问题是当客户端想要中止操作并停止从WCF服务下载数据时。 如果我在流上调用.close(),例如:serverReply.DataStream.Close();,那么它会阻塞并读取整个流从WCF服务直到结束才继续,而流可能非常大且网络不总是快速的。

这对网络资源使用来说非常不可取,因为基本上浪费在没有用处的数据上。由于basicHttpBinding仅允许两个并发TCP连接(默认情况下)到WCF服务服务器,因此它会阻止其他连接尝试,直到流被完全读取。

我可以增加并发连接的数量,但这将是一个糟糕的解决方案,因为它将为麻烦制造了一个漏洞。

例如,20个中止的下载仍在下载数据以将其丢弃。我需要完全停止传输。

在客户端上,流对象只是常规的Stream类,因此它只具有关闭方法,没有其他操作。

在代理对象上调用.close().abort()不起作用,也不会使用.dispose()或任何其他方法将其销毁。 在服务器端,我处理OperationContext.OperationCompleted事件,但直到从stream读取完数据后才会触发该事件。

那么问题是,我如何在不完全读取流的情况下关闭/中止它?

在发送非常大的文件时遇到了同样的问题...似乎肯定是漏掉了什么非常明显的东西。我可能不得不实现分块作为解决方法。 - John Nicholas
3个回答

1
经过调查,我发现WCF客户端将继续从流中读取,直到closeTimeout过期,然后它将中止连接。您可以缩短客户端的closeTimeout以最小化问题。
注意:您应该将释放流的代码包装在try/catch块中。stream.Dispose()方法会抛出TimeoutException,这违反了不在Dispose方法中抛出异常的准则。

0

你尝试过调整 binding.MaxBufferSize 吗?
你尝试过调整你的 app.config 文件设置吗?

<bindings>
  <wsHttpBinding>
    <binding name="default" maxReceivedMessageSize="2147483647"  maxBufferPoolSize="2147483647" 
             closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" >
      <readerQuotas  maxArrayLength="2147483647" maxBytesPerRead="4096" maxNameTableCharCount="16384"
                     maxDepth="64" maxStringContentLength="2147483647" />
    </binding>

  </wsHttpBinding>
</bindings>

我会尽量减少超时和缓冲区长度,并尝试中止或关闭,看看会发生什么。


1
我尝试过了,但没有帮助。一旦服务器开始发送流,它就不会停止,直到客户端接收完所有内容。关闭代理没有任何作用。 就像没有明显的方法来停止通信。 当客户端停止读取流时,我可以看到TCP窗口大小为零返回到服务器。服务器定期发送窗口大小为零的探测以查看客户端是否准备好再次读取。当然,客户端再次发送窗口大小为零。 这将永远持续下去,直到进程被终止。 - Yev
你尝试过仅使用HttpClient类读取流并查看是否可以关闭流吗? - Erez Robinson
我如何在不调用WCF服务的情况下完成这个操作?我进行了更多的研究,似乎没有办法从客户端关闭流。我尝试了另一种方法。我创建了另一个服务,一个控制服务,并尝试从那里(服务器端)关闭流。但是运气不佳,有些东西无法正常工作,它无法关闭或处理。 - Yev

0

我认为你仅仅是在关闭后接收缓冲区。您应将maxBufferSize设置为较低值。

您还可以通过包装流并覆盖读取来限制服务器上的数据量。如果客户端带宽较低,则使用较小的块,并从读取方法返回相应的计数以匹配实际读取的数量。这将限制缓冲区的填充速率。

我的自己对此进行的测试涉及编写一个NeverEndingStream并始终返回数据。在某些时候,我在客户端上调用close,然后几乎立即在服务器上调用close。这表明缓冲区仅仅被清空,因为显然它永远无法读取我的流直到结束。

如果您仍然遇到问题,则建议您跟踪覆盖流上的Read方法的定时。如果currentReadtime - lastReadTime > x,则可能会调用Close并引发异常。那肯定会杀死它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接