在TcpClient BeginConnect之后,应用程序在退出时挂起20秒

时间:2014-12-11 08:04:13

标签: c# asynchronous timeout tcpclient hang

我对TcpClient.BeginConnect()和TcpClient.EndConnect()方法的奇怪行为有疑问。

我使用BeginConnect()为Connect()方法添加超时(请参阅下面的扩展方法代码)。如果我连接,我调用EndConnect()并且一切正常,但如果我超时,我不能调用EndConnect(),因为它会阻塞大约20秒,所以我只是调用这个非阻塞代码: / p>

result.AsyncWaitHandle.Close();
result.AsyncWaitHandle.Dispose();
client.Close();

问题是当我在超时后关闭表单(在运行上面的代码之后),我的应用程序将#34;挂起"大约20秒。

有没有办法防止这种情况发生?

仅在应用程序退出时令人不快,所以如果没有别的办法可能会有一些肮脏的杀戮;]

一些注意事项:

  • 只有在我无法连接到服务器时才会发生挂起。
  • 退出时,表单将关闭,只有一些进程仍在后台运行。
  • 当我按下VS2013中的暂停按钮时应用程序挂起,我没有接受任何代码,所以我想这是一个自动创建的线程,其中挂起代码(EndConnect()?)被调用。
  • 当我在超时后等待大约20秒(应用程序响应)然后我关闭表单时没有挂起 - 所以这个阻止代码(EndConnect()?)会自动从其他某个线程调用。
  • 如果我调用方法TcpClient.Connect()(没有超时),我会被阻塞大约20秒,但退出时没有挂起。
  • 如果我在超时时运行此非阻塞代码:

                client.Client.Close();
                client.Client.Dispose();
                client.Close();
    

    它仍会在退出时挂起。

  • 即使我将BeginConnect(ip,port,null,null)更改为BeginConnect(ip,port,new AsyncCallback(ConnectCallback),null)并在ConnectCallback中调用客户端上的EndConnect()和Close(),应用程序仍然挂起exit(在退出之前调用ConnectCallback,其代码未挂起)。
  • 我写了大约20秒,但它更像是(20 - 超时)秒。在我的代码中,我有超时= 1秒,所以在这种情况下应用程序挂起大约20秒。

以下是我的连接代码:

    public bool Connect(string localMachineName)
    {
        // Get ips for local machine
        IPAddress[] ips;
        try
        {
            ips = Dns.GetHostEntry(localMachineName).AddressList.Where(
                    o => o.AddressFamily == AddressFamily.InterNetwork).ToArray();
        }
        catch { return false; }

        // loop and try to connect
        foreach (IPAddress ip in ips)
        {
            TcpClient c = new TcpClient();
            try
            {
                c.NoDelay = true;
                c.SendTimeout = 1000;     // this seems to not change anything
                c.ReceiveTimeout = 1000;  // this seems to not change anything

                // call connect with timeout - extension method
                // this leave after 1 sec (as required) but hangs app on exit
                c.Connect(ip, 8888, new TimeSpan(0, 0, 1));

                // if you comment previous line and uncomment code line below
                // it will block for about 20 secs and not hangs on apps exit
                // c.Connect(ip, 8888);

                if (c.Connected)
                {
                    MyClient = c;
                    break;
                }
                else
                {
                    MyClient = null;
                }
            }
            catch
            {
                c.Close();
                MyClient = null;
            }
        }
        return (MyClient != null) && (MyClient.Connected);
    }

以上代码使用扩展方法连接超时,此方法的代码如下(基于某些SO答案的代码):

    public static void Connect(this TcpClient client, IPAddress ip, int port, TimeSpan timeout)
    {
        // begin async connection
        IAsyncResult result = client.BeginConnect(ip, port, null, null);

        if (result.CompletedSynchronously)
        {
            client.EndConnect(result);
            return;
        }

        try
        {
            // wait until connected or timeouted or app shutdown
            WaitHandle[] handles = new WaitHandle[] { result.AsyncWaitHandle, shutdownEvent };
            int index = WaitHandle.WaitAny(handles, timeout);
            if (index == 0)
            {
                // connected
                client.EndConnect(result);
            }
            else if ((index == 1) || (index == WaitHandle.WaitTimeout))
            {
                // timeout or app shutdown

                /* 
                 * Enabling this will block on EndConnect for about 15-20 seconds
                client.EndConnect(result);
                client.Close();
                return;
                */

                /*
                 * Alternatively, after commenting above I tried this code,
                 * it doesn't block, but then it hangs for about 20 secs on app exit
                client.Client.Close();
                client.Client.Dispose();
                */

                // this doesn't block, but then it hangs for about 20 secs on app exit
                result.AsyncWaitHandle.Close();
                result.AsyncWaitHandle.Dispose();
                client.Close();
            }
        }
        catch (Exception e)
        {
            client.Close();
            throw new Exception("Connecting with timeout error: " + e.Message);
        }
    }

我对此问题进行了大量搜索,但无法查看与此特定问题相关的任何信息。请帮忙!

0 个答案:

没有答案