.net TcpClient开始连接超时

uqjltbpv  于 2022-11-26  发布在  .NET
关注(0)|答案(1)|浏览(167)

如何在C#中为BeginConnect异步调用设置自定义超时?这是非常有用的,当连接到一个主机时,有可能不监听给定的端口。每个这样的调用在释放线程之前都会浪费大约15s的时间。
我有以下代码,建议在许多stackoverflow答案:

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.Close()**调用,并等待上述15秒。是否可以以某种方式避免?

b1uwtaje

b1uwtaje1#

我编写了一个简单的测试程序,使用两种不同的技术来实现您的目标,同时也测试了您发布的确切代码。我无法重现您所描述的问题。无论是直接使用TcpClient还是Socket,对对象调用Close()都会导致连接操作立即完成(在完成所有异步完成、异常处理、线程同步等之后,时间不到十分之一秒)
请注意,在TcpClient的情况下,TcpClient类似乎有一个bug,它抛出了NullReferenceException而不是(如人们所期望的)ObjectDisposedException。这似乎是因为当Close()被调用时,TcpClientClient属性设置为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版本,等等。
在这种情况下,您应该具体说明环境中可能相关的特定方面。
如果上面的代码示例正常工作,并且没有演示您所描述的问题,那么您只需找出代码中的不同之处并找出问题的原因。在这种情况下,如果您仍然不能真正找出问题所在,那么您应该发布演示问题的a minimal, complete code example

相关问题