我正在使用 WCF 下载一个非常长的文件。它是一个基于 net-tcp 绑定的自托管服务。在客户端,我正在读取流并将其写入后台线程中的磁盘。在 UI 上,有一个取消按钮。我使用CancellationToken
.
问题是,
如果 Stream 为时过早(不是 EOF),则处理它需要很长时间。
在服务器(c#):
IO.Stream getFile(string filePath) {
return new IO.FileStream(filePath);
}
在客户端(vb):
using proxy as new ServiceReference1.TestServer
using wcfStrm = proxy.getFile("c:\100MB.dat")
using fileStrm = new FileStream("d:\destination\100MB.dat")
dim buff(256) as new Byte
while true
cancellationToken.ThrowIfCancellationRequested
Dim len = wcfStrm.Read(buff, 0, buff.Length)
if len > 0 then
fileStrm.write(buff, 0, len)
else
exit while
end if
end while
end using
end using ' <-------------- this hangs for 10Mins
end using
当CancellationToken
throws时OperationCancelledException
,所有三个 using 块都会尝试处理它们的资源。现在,当第二个 using 块尝试处理 时MessageBodyStream
,它会挂起 10 分钟。但是如果流被完全读取,那么它会很快退出。
我怀疑,这与ReceiveTimeout
10 分钟有关。所以我把它改成了 30 秒和中提琴!处置现在需要 30 秒。
还有一件事。Dispose
操作实际上超时。它吃掉我的东西OperationCancelledException
并产生一种TimeoutException
说法The sockket transfer timed out after 00:00:00... bla bla bla
以下是堆栈跟踪
System.TimeoutException: The socket transfer timed out after 00:00:00. You have exceeded the timeout set on your binding. The time allotted to this operation may have been a portion of a longer timeout.
at System.ServiceModel.Channels.SocketConnection.SetReadTimeout(TimeSpan timeout, Boolean synchronous, Boolean closing)
at System.ServiceModel.Channels.SocketConnection.ReadCore(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout, Boolean closing)
at System.ServiceModel.Channels.SocketConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout)
at System.ServiceModel.Channels.DelegatingConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout)
at System.ServiceModel.Channels.PreReadConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout)
at System.ServiceModel.Channels.SingletonConnectionReader.SingletonInputConnectionStream.ReadCore(Byte[] buffer, Int32 offset, Int32 count)
at System.ServiceModel.Channels.SingletonConnectionReader.SingletonInputConnectionStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at System.ServiceModel.Channels.MaxMessageSizeStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at System.ServiceModel.Channels.SingletonConnectionReader.Close(TimeSpan timeout)
at System.ServiceModel.Channels.SingletonConnectionReader.SingletonInputConnectionStream.Close()
at System.ServiceModel.Channels.DelegatingStream.Close()
at System.Xml.XmlBufferReader.Close()
at System.Xml.XmlBaseReader.Close()
at System.Xml.XmlBinaryReader.Close()
at System.ServiceModel.Dispatcher.StreamFormatter.MessageBodyStream.Close()
at System.IO.Stream.Dispose()
at ...somewhere in my code...
我不相信一旦没有完全阅读它就不能取消流。另一方面,我不能只是忘记流并且不处理就让它离开。它必须是一个阻塞等待直到安全释放的调用。
有人可以帮我吗?
编辑
堆栈跟踪显示:
' this is interesting
at System.Xml.XmlBinaryReader.Close() ' VVVVVVVVVVVVV
at System.ServiceModel.Dispatcher.StreamFormatter.MessageBodyStream.Close()
at System.IO.Stream.Dispose()
所以我将使用块更改为try-finally
块。我把wcfStrm.close
后面跟着wcfStrm.Dispose
。令我惊讶的是,关闭声明迅速通过,处置超时。现在,如果内部处置实际的罪魁祸首是Close
那么为什么显式关闭没有挂起?然后即使在流关闭时也再次挂起处置?