2010-06-04 86 views
1

我在使用異步套接字調用實現連接超時時遇到問題。.NET套接字超時 - 在關閉方法上阻塞

這個想法是我在一個Socket對象上調用BeginConnect,然後在超時時間結束後使用定時器在套接字上調用Close()

只要在GUI線程上創建套接字,Close方法立即返回,並執行回調方法,這就可以正常工作。但是,如果套接字是在任何其他線程上創建的,則Close方法會阻塞,直到發生默認IP超時。

代碼重現:

private Socket client; 

private void button1_Click(object sender, EventArgs e) { 
    // Creating the socket on a threadpool thread causes Close to block. 
    ThreadPool.QueueUserWorkItem((object state) => { 
     client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     IAsyncResult result = client.BeginConnect(IPAddress.Parse("144.1.1.1"), 23, new AsyncCallback(CallbackMethod), client); 

     // Wait for 2 seconds before closing the socket. 
     if (result.AsyncWaitHandle.WaitOne(2000)) { 
      MessageBox.Show("Connected."); 
     } else { 
      MessageBox.Show("Timed out. Closing socket..."); 
      client.Close(); 
      MessageBox.Show("Socket closed."); 
     } 
    }); 
} 

private void CallbackMethod(IAsyncResult result) { 
    MessageBox.Show("Callback started."); 
    Socket client = result.AsyncState as Socket; 
    try { 
     client.EndConnect(result); 
    } catch (ObjectDisposedException) { 
    } 
    MessageBox.Show("Callback finished."); 
} 

如果刪除QueueUserWorkItem線上,GUI線程創建的插座,插座會馬上閉合而不會阻塞。

任何人都可以闡明發生了什麼?
謝謝。

編輯 - System.Net跟蹤輸出似乎取決於是否它被連接GUI線程或者不同的線程上是不同的:

回答

0

有您嘗試刪除您在調用Socket.Close()時所使用的「MessageBox.Show」調用?

+0

無論MessageBox.Show如何,封閉都會發生。 即使將套接字的[LingerState](http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.lingerstate.aspx)屬性設置爲true,但不會超時幫幫我。 從MSDN:「下表描述了對於Enabled屬性和LingerTime屬性中存儲的LingerState屬性的可能值的Close方法的行爲。」 啓用LingerState並且將LingerTime設置爲零:「丟棄任何未決數據。對於面向連接的套接字(例如TCP),Winsock重置連接。」 – Mark 2010-06-05 03:52:06

+0

我試着用上面的程序重新編譯。我無法複製它。該程序不掛。 – feroze 2010-06-08 03:16:47

+0

在Windows 7和XP模式下,在任何版本的.NET Framework上,都會出現這種情況。我也可以在不同的機器上重現它。該程序不應該掛起,但在「超時,關閉套接字...」消息和「套接字關閉」之間應該有大約20秒的延遲。信息。 – Mark 2010-06-10 20:51:29

0

我無法確定的是它爲什麼會立即在GUI線程上關閉。我會嘗試在調用client.Close()之前調用client.Shutdown()。

我也嘗試在普通線程(Thread.Start())中運行套接字對象,而不是使用ThreadPool。這樣你可以保持對線程的引用,並自己調用Thread.Interrupt()和/或Thread.Abort()。

+0

上的說明獲取winsock跟蹤日誌。在套接字連接結果之前調用Shutdown SocketException - 「發送或接收數據的請求被禁止,因爲套接字未連接,並且(當使用sendto調用在數據報套接字上發送時)未提供地址」。 我目前使用單線程來啓動許多BeginConnects,然後使用System.Timers.Timer來根據需要超時套接字 - 我無法負擔爲每個連接使用新的線程。 :( – Mark 2010-06-05 04:08:33