我正在使用 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
当CancellationTokenthrows时OperationCancelledException,所有三个 using 块都会尝试处理它们的资源。现在,当第二个 using 块尝试处理 时MessageBodyStream,它会挂起 10 分钟。但是如果流被完全读取,那么它会很快退出。
我怀疑,这与ReceiveTimeout10 分钟有关。所以我把它改成了 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那么为什么显式关闭没有挂起?然后即使在流关闭时也再次挂起处置?