. net 4.5 SslStream -取消异步读/写调用

本文关键字:调用 异步 取消 SslStream net | 更新日期: 2023-09-27 18:08:38

是否有办法取消SslStream上的异步读或写任务?我已经尝试提供ReadAsync与CancellationToken,但它似乎不工作。当以下代码达到超时时间(task . delay)时,它调用CancellationTokenSource上的cancel, 应该取消读取任务,向调用方法返回一个错误,调用方法最终尝试再次读取,这会引发"当另一个写操作挂起时无法调用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;
    }

. net 4.5 SslStream -取消异步读/写调用

查看SslStream的文档,它不支持ReadAsync(它只是使用Stream的回退同步实现)。由于SslStream是一个装饰器流,因此如何安全地从底层流的超时中恢复并不明显,唯一明显的方法是重新初始化整个流管道。然而,考虑到底层流可能是不可搜索的,这可能不是一个好主意。

为了支持取消,流必须重写Stream.ReadAsync(Byte[], Int32, Int32, CancellationToken)。在文档中,NetworkStreamSslStream都没有覆盖ReadAsync的重载,而abstract Stream不可能实现通用的取消。有关支持取消的示例,请参阅FileStream并对比文档的不同之处。

因此,对于一个具体的情况,如果我们使用SslStream装饰HttpStream,那么在超时后,我们将希望通过在我们超时的位置打开HttpStream来恢复(使用Range标头)。但是没有办法使用IO.Stream类来通用地公开它。

最后,你应该考虑你的失败案例应该是什么。为什么ReadAsync会超时?在我能想到的大多数情况下,这应该是由于不可恢复的网络问题,这将需要重新初始化Stream

加分。您是否考虑过将超时行为重构为装饰器流?然后你可以把超时装饰器放到你的底层流上。

stream = new SslStream(
            new TimeoutStream(new FooStream(), Timespan.FromMilliseconds(1000)));