首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >TcpClient.ConnectAsync方法的取消支持

TcpClient.ConnectAsync方法的取消支持
EN

Stack Overflow用户
提问于 2019-05-17 21:28:21
回答 3查看 3K关注 0票数 4

我希望能得到一些关于在我正在研究的一篇文章中添加弹性的一些意见,其中涉及异步创建多个TcpClient连接到不同的服务器,一旦成功地建立了TCP连接,然后将TcpClient存储在某种集合中(这只是需求的一个摘录)。

到目前为止,这就是我所拥有的:

代码语言:javascript
复制
internal class Program
{
    private static readonly TcpClient _client = new TcpClient(AddressFamily.InterNetwork);
    private static SslStream _stream;

    private static async Task Main(string[] args)
    {
        var timeoutTask = Task.Delay(5000);
        var connectTask = _client.ConnectAsync("10.14.16.24", 56564);

        var completedTask = await Task.WhenAny(timeoutTask, connectTask);
        if (completedTask == timeoutTask)
            _client.Dispose();

        try
        {
            await connectTask;
            _stream = new SslStream(_client.GetStream(), false);
        }
        catch (SocketException e)
        {
            Console.WriteLine(e.Message);
        }
    }
}

returns :如果超时发生,connectTask状态仍然是"WaitingForActivation“,直到ConnectAsync方法返回FaultedRanToCompletion为止。如何取消此任务,同时知道ConnectAsync不支持CancellationToken

欢迎任何建议或改进。谢谢

EN

回答 3

Stack Overflow用户

发布于 2019-08-15 21:09:07

您的里程可能因您使用的.net而异

代码语言:javascript
复制
using System;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace TcpClientCancellation
{
    public static class Extensions
    {
        public static async Task ConnectAsync(this TcpClient tcpClient, string host, int port, CancellationToken cancellationToken) {
            if (tcpClient == null) {
                throw new ArgumentNullException(nameof(tcpClient));
            }

            cancellationToken.ThrowIfCancellationRequested();

            using (cancellationToken.Register(() => tcpClient.Close())) {
                try {
                    cancellationToken.ThrowIfCancellationRequested();

                    await tcpClient.ConnectAsync(host, port).ConfigureAwait(false);
                } catch (NullReferenceException) when (cancellationToken.IsCancellationRequested) {
                    cancellationToken.ThrowIfCancellationRequested();
                }
            }
        }
    }
}
票数 3
EN

Stack Overflow用户

发布于 2021-03-16 14:03:06

作为@Kelly Elton答案的扩展,似乎您应该抓住

  • 在.NET框架中4.x NullReferenceException
  • 在.NET内核2.x和3.x ObjectDisposedException
  • 在.NET 5 SocketException

所以也许正确的catch语句应该是

代码语言:javascript
复制
#if NET5_0 //_OR_GREATER?
catch (SocketException ex) when (ct.IsCancellationRequested)
#elif NETCOREAPP2_0_OR_GREATER
catch (ObjectDisposedException ex) when (ct.IsCancellationRequested)
#elif NETFRAMEWORK && NET40_OR_GREATER
catch (NullReferenceException ex) when (ct.IsCancellationRequested)
#else
#error Untested target framework, use with care!
catch (???) when (ct.IsCancellationRequested)
#endif
票数 3
EN

Stack Overflow用户

发布于 2021-08-31 17:32:03

我正在使用这些通用方法;它们可以为任何异步任务添加超时和取消令牌。您需要使用使用var tcpClient,以确保客户端在取消异常引发或主动释放客户端后被释放。

如果你看到任何问题,请告诉我,这样我就能相应地解决它。

代码语言:javascript
复制
public static async Task<T> RunTask<T>(Task<T> task, int timeout = 0, CancellationToken cancellationToken = default)
{
    await RunTask((Task)task, timeout, cancellationToken);
    return await task;
}

public static async Task RunTask(Task task, int timeout = 0, CancellationToken cancellationToken = default)
{
    if (timeout == 0) timeout = -1;

    var timeoutTask = Task.Delay(timeout, cancellationToken);
    await Task.WhenAny(task, timeoutTask);

    cancellationToken.ThrowIfCancellationRequested();
    if (timeoutTask.IsCompleted)
        throw new TimeoutException();

    await task;
}

使用

代码语言:javascript
复制
using var tcpClient = new TcpClient();
await RunTask(tcpClient.ConnectAsync("yourhost.com", 443), cancellationToken: CancellationToken.None);
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56193767

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档