C# .NET 4.5 SslStream-是否取消异步读/写调用?

C# .NET 4.5 SslStream-是否取消异步读/写调用?,c#,.net,asynchronous,sslstream,C#,.net,Asynchronous,Sslstream,有没有办法取消SslStream上的异步读或写任务?我曾尝试为ReadAsync提供CancellationToken,但它似乎不起作用。当以下代码达到其超时时间(Task.Delay)时,它调用CancellationTokenSource上的cancel,cancel应该取消读取任务,向调用方法返回错误,调用方法最终尝试再次读取,这会引发“当另一个写入操作挂起时无法调用BeginRead方法”异常 在我的特定应用程序中,我可以通过关闭套接字并重新连接来解决这个问题,但是重新建立连接会带来很高

有没有办法取消SslStream上的异步读或写任务?我曾尝试为ReadAsync提供CancellationToken,但它似乎不起作用。当以下代码达到其超时时间(Task.Delay)时,它调用CancellationTokenSource上的cancel,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;
    }
private async Task ReadAsync(字节[]缓冲区、整数偏移量、整数计数、日期时间超时)
{
CancellationTokenSource CancellationTokenSource=新的CancellationTokenSource();
if(socket.Poll(Convert.ToInt32(timeout.RemainingTimeout().totalmillizes)*1000,SelectMode.SelectRead)=true)
{
Task readTask=stream.ReadAsync(缓冲区、偏移量、计数、cancellationTokenSource.Token);
if(wait Task.WhenAny(readTask,Task.Delay(timeout.RemainingTimeout())==readTask)
返回readTask.Result;
其他的
cancellationTokenSource.Cancel();
}
返回-1;
}

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

为了支持取消,流必须重写
stream.ReadAsync(Byte[],Int32,Int32,CancellationToken)
。在文档中,无论是
NetworkStream
还是
SslStream
都不会覆盖消费取消所需的
ReadAsync
重载(并且
抽象流
不可能实现通用取消)。有关支持取消的示例,请参见并对比文档的不同之处

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

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

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

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

我会考虑你的“超越梦想”的想法。为了提供更多信息,SslStream正在“装饰”从套接字获得的网络流。它超时的原因有很多,特别是在我使用它时,可能不是因为不可恢复的网络问题,所以正如我所说的,重新连接并不理想。另外,你从哪里读到SslStream不支持ReadAsync?查看MSDN,它说“异步读取当前流中的一系列字节,根据读取的字节数提升流中的位置,并监视取消请求。”@Matt查看参考源:遗憾的是,即使在.NET 4.8中,也没有ReadAsync。幸运的是,.NET Core(和.NET 5)似乎最终支持它: