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

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

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

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

问题是当我在超时后关闭表单(在运行代码之后)我的应用程序将“挂起”大约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(),应用程序仍会挂起(ConnectCallback)在退出之前被调用并且其代码没有挂起)。
  • 我写了大约20秒,但它更像是(20 – 超时)秒。 在我的代码II中有超时= 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); } } 

我搜索了很多关于这个问题的内容,但是看不到与这个特定问题相关的任何信息。 请帮忙!