TcpClient BeginConnect timeout



如何在 c# 中为 BeginConnect 异步调用设置自定义超时?它非常有用,同时连接到主机时,可能会不侦听给定端口。每次这样的调用在释放线程之前都会浪费大约 15 秒的时间。

我有以下代码,正如许多堆栈溢出答案中所建议的那样:

public bool Test()
{
     using (var tcp = new TcpClient())
     {
         var c = tcp.BeginConnect(IPAddress.Parse("8.8.8.8"), 8080, null, null);
         var success = c.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
         if (!success)
         {
             Console.WriteLine("Before cleanup");
             tcp.Close();
             tcp.EndConnect(c);
             Console.WriteLine("After cleanup");
             throw new Exception("Failed to connect.");
         }
     }
     return true;
}

但是,这不起作用。实际上,在调用之后,该函数进入"if"开关,但它在 tcp 上立即阻塞。关闭() 调用并等待提到的 15 秒。能以某种方式避免吗?

我编写了一个简单的测试程序,使用两种不同的技术来实现您的目标,并测试您发布的确切代码。我无法重现您描述的问题。无论我直接使用 TcpClient 还是Socket,在对象上调用 Close() 都会导致连接操作立即完成(好吧,在所有异步完成、异常处理、线程同步等之后,不到 1/10 秒)。

请注意,在TcpClient的情况下,TcpClient类似乎有一个错误,因为它抛出NullReferenceException而不是(如人们所期望的那样)ObjectDisposedException。这似乎是因为TcpClient在调用 Close() 时将 Client 属性设置为 null,但在调用完成委托时尝试使用该值。哎呀。

这意味着在您的代码中,调用方将看到NullReferenceException,而不是您似乎想要抛出的Exception。但这似乎本身并不会导致实际的延迟。

这是我的测试程序:

class Program
{
    static void Main(string[] args)
    {
        _TestWithSocket();
        _TestWithTcpClient();
        try
        {
            _TestSOCode();
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception: " + e);
        }
    }
    private static void _TestSOCode()
    {
        using (var tcp = new TcpClient())
        {
            var c = tcp.BeginConnect(IPAddress.Parse("8.8.8.8"), 8080, null, null);
            var success = c.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
            if (!success)
            {
                Console.WriteLine("Before cleanup");
                tcp.Close();
                tcp.EndConnect(c);
                Console.WriteLine("After cleanup");
                throw new Exception("Failed to connect.");
            }
        }
    }
    private static void _TestWithTcpClient()
    {
        TcpClient client = new TcpClient();
        object o = new object();
        Console.WriteLine("connecting TcpClient...");
        client.BeginConnect("8.8.8.8", 8080, asyncResult =>
        {
            Console.WriteLine("connect completed");
            try
            {
                client.EndConnect(asyncResult);
                Console.WriteLine("client connected");
            }
            catch (NullReferenceException)
            {
                Console.WriteLine("client closed before connected: NullReferenceException");
            }
            catch (ObjectDisposedException)
            {
                Console.WriteLine("client closed before connected: ObjectDisposedException");
            }
            lock (o) Monitor.Pulse(o);
        }, null);
        Thread.Sleep(1000);
        Stopwatch sw = Stopwatch.StartNew();
        client.Close();
        lock (o) Monitor.Wait(o);
        Console.WriteLine("close took {0:0.00} seconds", sw.Elapsed.TotalSeconds);
        Console.WriteLine();
    }
    private static void _TestWithSocket()
    {
        Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
        object o = new object();
        Console.WriteLine("connecting Socket...");
        socket.BeginConnect("8.8.8.8", 8080, asyncResult =>
        {
            Console.WriteLine("connect completed");
            try
            {
                socket.EndConnect(asyncResult);
                Console.WriteLine("socket connected");
            }
            catch (ObjectDisposedException)
            {
                Console.WriteLine("socket closed before connected");
            }
            lock (o) Monitor.Pulse(o);
        }, null);
        Thread.Sleep(1000);
        Stopwatch sw = Stopwatch.StartNew();
        socket.Close();
        lock (o) Monitor.Wait(o);
        Console.WriteLine("close took {0:0.00} seconds", sw.Elapsed.TotalSeconds);
        Console.WriteLine();
    }
}

遗憾的是,您没有提供实际的完整代码示例来演示该问题。如果在您的环境中,上面的代码演示了您描述的问题,那么由于它在我的环境中没有这样做,这显然意味着您的环境中存在导致问题的原因。不同的操作系统版本,不同的.NET版本等。

在这种情况下,您应该具体说明可能相关的环境的特定方面。

如果上面的代码示例按预期工作,并且没有演示您描述的问题,那么您只需要找出您拥有的代码中有哪些不同并导致问题。在这种情况下,如果您仍然无法真正找出问题所在,则应发布一个最小完整的代码示例来演示问题。

相关内容

  • 没有找到相关文章

最新更新