一尘不染

异步网络操作永远不会完成

c#

我有几个异步网络操作,它们返回的任务可能永远不会完成:

  1. UdpClient.ReceiveAsync 不接受 CancellationToken
  2. TcpClient.GetStream返回一个NetworkStream不遵守CancellationTokenon的Stream.ReadAsync(仅在操作开始时检查取消)

两者都等待 可能 永远不会出现的消息(例如,由于丢包或无响应)。这意味着我有无法完成的 幻像
任务,将永远不会运行的继续操作以及已使用的套接字处于保留状态。我知道我可以使用TimeoutAfter,但这只会解决继续问题。

那我该怎么办?


阅读 284

收藏
2020-05-19

共1个答案

一尘不染

因此,我在其上IDisposable创建了一个扩展方法,该方法创建了一个CancellationToken在超时时处理连接的方法,因此任务完成,一切都继续进行:

public static IDisposable CreateTimeoutScope(this IDisposable disposable, TimeSpan timeSpan)
{
    var cancellationTokenSource = new CancellationTokenSource(timeSpan);
    var cancellationTokenRegistration = cancellationTokenSource.Token.Register(disposable.Dispose);
    return new DisposableScope(
        () =>
        {
            cancellationTokenRegistration.Dispose();
            cancellationTokenSource.Dispose();
            disposable.Dispose();
        });
}

而且用法非常简单:

try
{
    var client = new UdpClient();
    using (client.CreateTimeoutScope(TimeSpan.FromSeconds(2)))
    {
        var result = await client.ReceiveAsync();
        // Handle result
    }
}
catch (ObjectDisposedException)
{
    return null;
}

额外信息:

public sealed class DisposableScope : IDisposable
{
    private readonly Action _closeScopeAction;
    public DisposableScope(Action closeScopeAction)
    {
        _closeScopeAction = closeScopeAction;
    }
    public void Dispose()
    {
        _closeScopeAction();
    }
}
2020-05-19