NetworkStream.ReadAsync与取消标记从未取消 [英] NetworkStream.ReadAsync with a cancellation token never cancels

查看:633
本文介绍了NetworkStream.ReadAsync与取消标记从未取消的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的证明。结果
任何想法是错误的这个code?

  [TestMethod的]
    公共无效TESTTEST()
    {
        VAR TCP =新的TcpClient(){ReceiveTimeout = 5000,的SendTimeout = 20000};
        tcp.Connect(IPAddress.Parse(176.31.100.115),25);
        。BOOL OK =读(tcp.GetStream())等待(30000);
        Assert.IsTrue(OK);
    }    异步任务读取(的NetworkStream流)
    {
        使用(VAR cancellationTokenSource =新CancellationTokenSource(5000))
        {
            INT receivedCount;
            尝试
            {
                VAR缓冲=新的字节[1000];
                receivedCount =等待stream.ReadAsync(缓冲,0,1000,cancellationTokenSource.Token);
            }
            赶上(TimeoutException异常E)
            {
                receivedCount = -1;
            }
        }
    }


解决方案

我终于找到了解决办法。使用Task.WaitAny延迟任务(Task.Delay)相结合的异步调用。当延迟的IO任务逝去前,关闭流。这将强制任务停止。你应该正确处理对IO任务异步例外。而且你应该添加后续任务为延迟任务和IO任务。

这也与TCP连接工作。关闭在另一个线程的连接(你可以认为它是延迟任务线程),使用/等待就此停止强制所有异步任务。

- 编辑 -

另一种清洁的解决方案通过@vtortola建议:使用取消标记注册到stream.Close呼叫:

 异步任务读取(的NetworkStream流)
{
    使用(VAR cancellationTokenSource =新CancellationTokenSource(5000))
    {
        使用(cancellationTokenSource.Token.Register(()=> stream.Close()))
        {
            INT receivedCount;
            尝试
            {
                VAR缓冲=新的字节[1000];
                receivedCount =等待stream.ReadAsync(缓冲,0,1000,cancellationTokenSource.Token);
            }
            赶上(TimeoutException异常E)
            {
                receivedCount = -1;
            }
        }
    }
}

Here the proof.
Any idea what is wrong in this code ?

    [TestMethod]
    public void TestTest()
    {
        var tcp = new TcpClient() { ReceiveTimeout = 5000, SendTimeout = 20000 };
        tcp.Connect(IPAddress.Parse("176.31.100.115"), 25);
        bool ok = Read(tcp.GetStream()).Wait(30000);
        Assert.IsTrue(ok);
    }

    async Task Read(NetworkStream stream)
    {
        using (var cancellationTokenSource = new CancellationTokenSource(5000))
        {
            int receivedCount;
            try
            {
                var buffer = new byte[1000];
                receivedCount = await stream.ReadAsync(buffer, 0, 1000, cancellationTokenSource.Token);
            }
            catch (TimeoutException e)
            {
                receivedCount = -1;
            }
        }
    }

解决方案

I finally found a workaround. Combine the async call with a delay task (Task.Delay) using Task.WaitAny. When the delay elapses before the io task, close the stream. This will force the task to stop. You should handle the async exception on the io task correctly. And you should add a continuation task for both the delayed task and the io task.

It also work with tcp connections. Closing the connection in another thread (you could consider it is the delay task thread) forces all async tasks using/waiting for this connection to stop.

--EDIT--

Another cleaner solution suggested by @vtortola: use the cancellation token to register a call to stream.Close:

async Task Read(NetworkStream stream)
{
    using (var cancellationTokenSource = new CancellationTokenSource(5000))
    {
        using(cancellationTokenSource.Token.Register(() => stream.Close()))
        {
            int receivedCount;
            try
            {
                var buffer = new byte[1000];
                receivedCount = await stream.ReadAsync(buffer, 0, 1000, cancellationTokenSource.Token);
            }
            catch (TimeoutException e)
            {
                receivedCount = -1;
            }
        }
    }
}

这篇关于NetworkStream.ReadAsync与取消标记从未取消的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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