2011-04-23 168 views
7

我試圖在異步HTTP客戶端中重用套接字,但我無法第二次連接到主機。我基本上把我的異步HTTP客戶端狀態機具有以下狀態:重用異步套接字:後續連接嘗試失敗

  • 可用:插座可供使用
  • 連接:將插座連接到端點
  • 發送:套接字發送數據到端點
  • 接收:插座從端點
  • 無法接收數據:有一個插座故障
  • 清理:清理套接字狀態

在連接狀態下我打電話BeginConnect

private void BeginConnect() 
{ 
    lock (_sync) // re-entrant lock 
    { 
     IPAddress[] addersses = Dns.GetHostEntry(_asyncTask.Host).AddressList; 

     // Connect to any available address 
     IAsyncResult result = _reusableSocket.BeginConnect(addersses, _asyncTask.Port, new AsyncCallback(ConnectCallback), null); 
    } 
} 

回調方法改變狀態Sending一次成功的連接已經建立:

private void ConnectCallback(IAsyncResult result) 
{ 
    lock (_sync) // re-entrant lock 
    { 
     try 
     { 
      _reusableSocket.EndConnect(result); 

      ChangeState(EClientState.Sending); 
     } 
     catch (SocketException e) 
     { 
      Console.WriteLine("Can't connect to: " + _asyncTask.Host); 
      Console.WriteLine("SocketException: {0} Error Code: {1}", e.Message, e.NativeErrorCode); 
      ThreadPool.QueueUserWorkItem(o => 
      { 
       // An attempt was made to get the page so perform a callback 
       ChangeState(EClientState.Failed); 
      }); 
     } 
    } 
} 

在我Shutdown的清理插座和Disconnect帶重用標記:

在超時

後續調用BeginConnect結果和例外:

SocketException:連接嘗試 失敗,因爲連接的方沒有 一段 時間後沒有正確答覆或建立的連接失敗 因爲連接主機未能響應 XX.XXX.XX.XX:80

錯誤代碼:10060

下面是狀態跟蹤:

Initializing... 
Change State: Connecting 
Change State: Sending 
Change State: Receiving 
Change State: CleanUp 
Callback:  Received data from client 0 // <--- Received the first data 
Change State: Available 
Change State: Connecting // <--- Timeout when I try to reuse the socket to connect to a different endpoint 

什麼我必須做的,以便能夠重新使用套接字連接到不同的主機?

注意:我有 而不是 試圖重新連接到同一主機,但 我假設 發生同樣的事情(即無法連接)。

更新
我發現下面的音符在documentation of BeginConnect

如果此套接字之前已斷開連接,然後BeginConnect必須在一個線程,將不會退出,直到操作完成調用。這是底層提供商的限制。此外,使用的EndPoint必須不同。

我開始懷疑我的問題是否與該問題有關...我正在連接到不同的EndPoint,但它們是什麼意思,我們稱之爲BeginConnect的線程在操作完成之前不能退出?

更新2.0:
我問了related question,我嘗試使用「異步家庭」調用,而不是「開始家庭」電話,但我得到了同樣的問題!

回答

2

我對此問題發表了評論:what is benefit from socket reuse in C#關於使用套接字重複使用Disconnect(true)/DisconnectEx()這可能對您有所幫助。

個人而言,我認爲這是客戶端代碼中的一項優化。

重新更新1到您的問題;不,你會得到一個AbortedOperation異常,如果是這種情況(見這裏:VB.NET 3.5 SocketException on deployment but not on development machine)和文檔是錯誤的,如果你在Vista或更高版本上運行,因爲它不強制執行「線程必須存在,直到重疊的I/O完成「規則,以前的操作系統強制執行。

正如我在回覆鏈接問題時所說的那樣;使用此功能進行出站連接建立幾乎沒有意義。它很可能是最初添加到Winsock API以支持入站連接上的AcceptEx()的套接字重用,其中在使用TransmitFile()向客戶端發送文件的非常繁忙的Web服務器上(這是發生斷開連接似乎已經發生的地方) 。該文檔聲明它不能很好地與TIME_WAIT配合使用,因此將它用於啓動主動關閉(因此將套接字放入TIME_WAIT,請參閱here)的連接並沒有什麼意義。

你能解釋一下爲什麼你認爲這種微型優化在你的情況下實際上是必要的嗎?

+0

我不知道爲什麼我沒有回答你的問題,但我做這種微型優化的原因是因爲我每秒抓取300多個網頁,每次抓取都要求我關閉舊套接字,處置它並打開一個新套接字。該應用程序運行時間很長,因此最終會導致內存抖動並降低系統速度。性能是這種情況下的關鍵。 – Kiril 2011-11-24 06:24:44

0
+0

它看起來像'NetTcpBinding'是一個WCF的東西,我使用原始的'套接字'...我沒有看到我怎麼可以利用'NetTcpBinding'與原始的'套接字'。 – Kiril 2011-04-27 11:58:23

+0

ups。我認爲這是一樣的。我通常把它放到應用程序配置是這樣的:<?XML版本= 「1.0」?> <結構> <添加地址= 「*」 MAXCONNECTION = 「32768」/> NickD 2011-04-27 13:05:04

+0

我不認爲套接字受這些設置的影響。許多套接字應用甚至可能沒有app.config,但感謝您的答案:)。 – Kiril 2011-04-27 13:10:49