我有几个异步网络操作返回可能永远不会完成的任务:
> UdpClient.ReceiveAsync不接受CancellationToken
> TcpClient.GetStream返回一个不遵循Stream.ReadAsync上的CancellationToken的NetworkStream(仅在操作开始时检查取消)
两者都在等待可能永远不会发生的消息(例如因丢包或没有响应).这意味着我有永远不会完成的幻像任务,永远不会运行的延续和使用套接字.我知道我可以使用TimeoutAfter
,但这只会解决延续问题.
那我该怎么办?
解决方法
所以我在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(); } }