.NET 4.5 SslStream - 取消异步读/写打电话? [英] .NET 4.5 SslStream - Cancel a asynchronous read/write call?

查看:245
本文介绍了.NET 4.5 SslStream - 取消异步读/写打电话?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法取消异步读取或在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆