.NET 4.5 SslStream - 取消异步读/写打电话? [英] .NET 4.5 SslStream - Cancel a asynchronous read/write call?
问题描述
有没有办法取消异步读取或在SslStream写任务吗?我曾尝试提供ReadAsync用的CancellationToken但它不出现工作。当以下code到达它的超时(在Task.Delay),它呼吁取消对CancellationTokenSource其中的应的取消读出任务,返回一个错误给调用方法,并调用方法,最终尝试再次读取,这引起了一个的方法的BeginRead无法调用下一次写操作挂起的异常。
在我的具体应用,我可以解决这个由closeing插座,然后重新连接,但与重建的连接,因此不太理想有关的高开销。
专用异步任务< INT> ReadAsync(字节[]缓冲区,诠释抵消,诠释计数,日期时间超时)
{
CancellationTokenSource cancellationTokenSource =新CancellationTokenSource(); 如果(socket.Poll(Convert.ToInt32(timeout.RemainingTimeout()。TotalMilliseconds)* 1000,SelectMode.SelectRead)==真)
{
任务< INT> readTask = stream.ReadAsync(缓冲区,偏移,计数,cancellationTokenSource.Token); 如果(AWAIT Task.WhenAny(readTask,Task.Delay(timeout.RemainingTimeout()))== readTask)
返回readTask.Result;
其他
cancellationTokenSource.Cancel();
}
返回-1;
}
纵观DOC为 SslStream
,它不支持 ReadAsync
(它只是使用从流
回退同步实施)。因为SslStream是一个装饰流,是不明显如何安全地从底层流上超时恢复,唯一明显的方法是重新初始化整个流管道。然而鉴于底层流可能不是可查找,再次这可能不是主意。
有关支持取消,流必须覆盖 Stream.ReadAsync(字节[],的Int32,的Int32,的CancellationToken)
。在文档中,既不的NetworkStream
也不 SslStream
覆盖的过载 ReadAsync
需要消耗取消(和抽象流
不可能实现通用取消)。对于那些取消支持的示例,请参见的FileStream 并对比文件的不同之处。
因此,对于一个具体的例子,如果我们在装修 HttpStream
使用 SslStream
然后在超时后,我们会想通过打开 HttpStream
回到我们超时(使用范围
头)的位置恢复。但是,没有办法公开的一般使用 IO.Stream
类。
最后,你应该考虑你的失败案例应该是什么。为什么会 ReadAsync
超时?在大多数我能想到的情况下,它应该是由于不可恢复的网络问题,这将需要在流
被初始化。
红利点。你有没有考虑重构你的超时行为变成一个装饰流?然后,您可以放置超时装饰到您的底层流。
=流新SslStream(
新TimeoutStream(新FooStream(),Timespan.FromMilliseconds(1000)));
Is there any way to cancel a asynchronous read or write task on a SslStream? I have tried providing ReadAsync with a CancellationToken but it doesnt appear to work. When the following code reaches it's timeout (the Task.Delay), it calls cancel on the CancellationTokenSource which should cancel the read task, returns a error to the calling method, and the calling method eventually tries to read again, which raises a "The BeginRead method cannot be called when another write operation is pending" exception.
In my specific application I could work around this by closeing the socket and reconnecting, but there is a high overhead associated with reestablishing the connection so it is less than ideal.
private async Task<int> ReadAsync(byte[] buffer, int offset, int count, DateTime timeout)
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
if (socket.Poll(Convert.ToInt32(timeout.RemainingTimeout().TotalMilliseconds) * 1000, SelectMode.SelectRead) == true)
{
Task<int> readTask = stream.ReadAsync(buffer, offset, count, cancellationTokenSource.Token);
if (await Task.WhenAny(readTask, Task.Delay(timeout.RemainingTimeout())) == readTask)
return readTask.Result;
else
cancellationTokenSource.Cancel();
}
return -1;
}
Looking at the doc for SslStream
, it does not support ReadAsync
(it simply uses the fallback synchronous implementation from Stream
). Since SslStream is a decorator Stream, is isn't obvious how to safely recover from a timeout on the underlying Stream, and the only obvious way would be to re-initialize the entire Stream pipeline. However given that the underlying stream might not be seekable, again this might not be idea.
For support of cancellation, the stream would have to override Stream.ReadAsync(Byte[], Int32, Int32, CancellationToken)
. In the documentation, neither NetworkStream
nor SslStream
overrides the overload of ReadAsync
required to consume cancellation (and abstract Stream
couldn't possibly implement generic cancellation). For an example where cancellation IS supported, see FileStream and contrast how the documentation differs.
So for a concrete case, if we were decorating HttpStream
using SslStream
then after a timeout we would want to recover by opening the HttpStream
back at the position where we timed out (using the Range
header). But there is no way to expose that generically using the IO.Stream
class.
Finally you should consider what your failure case should be. Why would ReadAsync
timeout? In the majority of cases I can think of, it should be due to unrecoverable network issues, which would necessitate the Stream
being reinitialized.
Bonus point. Have you considered refactoring out your Timeout behaviour into a decorator Stream? You could then place the timeout decorator onto your underlying stream.
stream = new SslStream(
new TimeoutStream(new FooStream(), Timespan.FromMilliseconds(1000)));
这篇关于.NET 4.5 SslStream - 取消异步读/写打电话?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!