2010-03-31 140 views
16

在客戶端,我需要知道何時/如果套接字連接已斷開。然而,Socket.Connected屬性總是返回true,即使在服務器端已斷開連接並嘗試通過它發送數據之後。任何人都可以幫我弄清楚這裏發生了什麼。我需要知道套接字何時斷開連接。如何判斷套接字何時斷開

 Socket serverSocket = null; 
     TcpListener listener = new TcpListener(1530); 
     listener.Start(); 
     listener.BeginAcceptSocket(new AsyncCallback(delegate(IAsyncResult result) 
     { 
      Debug.WriteLine("ACCEPTING SOCKET CONNECTION"); 
      TcpListener currentListener = (TcpListener)result.AsyncState; 
      serverSocket = currentListener.EndAcceptSocket(result); 
     }), listener); 


     Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     Debug.WriteLine("client socket connected: " + clientSocket.Connected);//should be FALSE, and it is 
     clientSocket.Connect("localhost", 1530); 
     Debug.WriteLine("client socket connected: " + clientSocket.Connected);//should be TRUE, and it is 

     Thread.Sleep(1000); 
     serverSocket.Close();//closing the server socket here 
     Thread.Sleep(1000); 

     clientSocket.Send(new byte[0]);//sending data should cause the socket to update its Connected property. 
     Debug.WriteLine("client socket connected: " + clientSocket.Connected);//should be FALSE, but its always TRUE 
+0

請參閱http://stackoverflow.com/questions/722240/instantly-detect-client-disconnection-from-server-socket進一步討論。 – EricLaw 2013-07-11 22:58:04

回答

0

確實的clientSocket.Send()方法等待該分組或者是ACK/nack'd?

如果不是你的代碼正在飛到下一行,而套接字仍然試圖找出發生了什麼。

+0

您可以在發送後放置一個Thread.Sleep。無論等待clientSocket.Connected保持多久。 – BowserKingKoopa 2010-03-31 19:00:16

9

做了一些測試之後,看起來Socket.Connected的文檔是錯誤的,或者至少是誤導性的。在調用clientSocket.close()後,clientSocket.Connected只會變爲false。我認爲這是對原始C Berkeley套接字API及其術語的倒退。當一個套接字有一個與之關聯的本地地址時,套接字被綁定,並且一個套接字在與其關聯的遠程地址時被連接。即使遠程端已關閉連接,本地套接字仍具有關聯,因此它仍處於「連接」狀態。

然而,這裏是工作的方法:

!(socket.Poll(0, SelectMode.SelectRead) && socket.Available == 0) 

它依賴於這一事實,在關閉​​的連接將被標記,即使沒有數據可用的可讀性。

如果您想要檢測諸如斷開的網絡電纜或突然關閉的計算機等情況,情況會更復雜一些。在這些情況下,您的計算機永遠不會收到一個表明套接字已關閉的數據包。它需要通過發送數據包並注意到沒有響應返回來檢測到遠程端已消失。作爲協議的一部分,您可以在應用程序級別執行此操作,也可以使用TCP KeepAlive選項。使用TCP Keep Alive來自.NET不是特別容易;你可能會更好地在你的協議中建立一個keep-alive機制(或者,你可以問一個單獨的問題:「如何在.NET中啓用TCP Keep Alive並設置保持活動時間間隔?」)。

+0

即使在服務器端連接已關閉後,socket.Poll(0,SelectMode.SelectRead)始終會爲我返回true。 – BowserKingKoopa 2010-03-31 20:58:14

+0

此外msdn文檔說,輪詢方法無法檢測到某些情況,如「網線斷了,或者遠程主機非正常關閉」。我只想知道服務器端套接字是否存在,我不在乎它爲什麼不存在。 – BowserKingKoopa 2010-03-31 21:10:55

+0

@BrowserKingKoopa:哎呀!我最初發布的代碼測試了套接字*斷開連接*。我修復了它。當遠程端斷開連接時,Poll()將返回true,但socket.Available將爲0. 我還添加了一段關於處理斷開的網絡電纜的段落。 – 2010-03-31 22:06:28

3

也許解決方法是通過它發送一些虛擬數據並檢查它是否超時?

2

我建議剝離更高級別的語言內容,並探究下級IO會發生什麼。

我寫的isectd最低(在sourceforge上查找)。使用select()系統調用,關閉套接字的描述符變爲已準備好,當isectd嘗試recv()時,可以確認套接字的斷開狀態。

作爲一種解決方案,我建議不要編寫自己的套接字IO並使用其他人的中間件。那裏有很多優秀的候選人。不要忘記考慮簡單的排隊服務。

PS。我會提供所有以上的URL,但我的聲望(1)不允許。

4

正常寫入您的套接字。你會知道什麼時候它被異常斷開,說你的數據無法傳遞。

如果你沒有任何東西可寫...那麼誰在乎它是否斷開?它現在可能會斷開連接,但在你需要之前回來 - 爲什麼還要把它拆下來,然後循環重新連接,直到鏈接被修復...特別是當你還沒有話要說什麼?

如果它困擾你,在你的協議中實現一個存活。然後你每30秒鐘就會有話要說。

+0

+1如果服務器發送所有數據並且它不保持活動狀態,它應該關閉套接字,並且客戶端應該處理它的屬性。如果它從客戶端接收到所有需要的數據,它也只是關閉連接,服務器將處理它。 你應該在s.Receive/s.send上發現異常,發現有人斷開連接時,Poll也會在斷開連接的套接字上拋出異常 – hoodoos 2010-04-24 20:44:52

+0

套接字可以雙向工作,主要問題是當你使用套接字使用push但套接字是D/C沒有你知道它,所以你沒有數據,因爲閱讀網絡流給數據,但沒有錯誤。 – 2017-11-22 09:46:18