有没有办法取消 SslStream 上的异步读取或写入任务?我尝试为 ReadAsync 提供 CancellationToken 但它似乎不起作用。当以下代码达到超时(Task.Delay)时,它会调用 CancellationTokenSource 上的取消,should取消读取任务,向调用方法返回错误,并且调用方法最终尝试再次读取,这会引发“当另一个写入操作挂起时无法调用 BeginRead 方法”异常。
在我的特定应用程序中,我可以通过关闭套接字并重新连接来解决此问题,但建立连接会产生很高的开销,因此不太理想。
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;
}
查看文档SslStream
,它不支持ReadAsync
(它只是使用后备同步实现Stream
)。由于 SslStream 是一个装饰器 Stream,因此如何安全地从底层 Stream 的超时中恢复并不明显,唯一明显的方法是重新初始化整个 Stream 管道。然而,考虑到底层流可能不可查找,这也可能不是一个主意。
为了支持取消,流必须重写Stream.ReadAsync(Byte[], Int32, Int32, CancellationToken)
。在文档中,两者都没有NetworkStream
nor SslStream
覆盖超载ReadAsync
需要消耗取消(和abstract Stream
不可能实现通用取消)。有关支持取消的示例,请参阅文件流并对比文档的不同之处。
所以对于一个具体的例子来说,如果我们要装饰HttpStream
using SslStream
然后超时后我们希望通过打开来恢复HttpStream
回到我们超时的位置(使用Range
标题)。但没有办法一般地使用IO.Stream
class.
最后你应该考虑你的失败案例应该是什么。为什么会ReadAsync
暂停?在我能想到的大多数情况下,这应该是由于不可恢复的网络问题,这需要Stream
正在重新初始化。
加分点。您是否考虑过将超时行为重构为装饰器流?然后,您可以将超时装饰器放置到底层流上。
stream = new SslStream(
new TimeoutStream(new FooStream(), Timespan.FromMilliseconds(1000)));
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)