2009-09-02 67 views
8

我正在C#中開發一個服務器,它只能接受一個客戶端,我需要知道這個客戶端何時斷開連接才能接受另一個連接請求。在.NET中檢測客戶端斷開連接的最佳實踐?

我正在使用第一個Socket連續監聽與Socket.BeginAccept的連接請求並接受或拒絕客戶端。當客戶端被接受時,由Socket.EndAccept返回的新Socket被用於客戶端和服務器之間的通信。然後,服務器通過Socket.Begin/EndReceive等待來自客戶端的命令併發送響應。服務器使用類似Telnet的協議,這意味着每個命令和每個響應行都必須以\r\n結尾。

爲了檢測客戶端是否已斷開連接,我安裝了一個定時器,它每隔500毫秒向客戶端發送一條空消息(「\r\n」)。如果客戶端斷開連接,Socket會引發異常。此異常由關閉當前會話並接受新連接的服務器捕獲。該解決方案是健壯的,但意味着不必要的網絡流量,並且必須由客戶端正確處理,客戶端必須在獲得實際響應之前過濾虛擬消息。

我試圖發送一個空的緩衝區(Socket.Send(new byte[1], 0, 0)),但它似乎不適用於方向server-> client。

另一種解決方案可能是處理Socket.EndReceive返回0字節的情況。它適用於在「空閒」時間發生斷開的情況。但是,如果客戶端在消息轉移期間斷開連接,服務器並不總是看到它並且無限期地等待。

我已經看到了關於這個問題的幾個線程和問題,但我從來沒有見過任何好的解決方案。

所以我的問題是:在.Net中檢測斷開連接的最佳方法是什麼?

回答

4

唯一的其他選擇是TCP是讓TCP每隔一段時間發送一次keep-alive,這仍然是輪詢,比如你正在做什麼,但是在TCP層處理,所以你的協議不會不需要知道。

但是沒有辦法繞過輪詢,因爲如果不向其他客戶端發送任何內容並獲得響應,則無法知道它是否仍處於連接狀態。

通過有狀態數據包檢測(如標準NAPT)進行通信時,保持活動狀態可能也是必需的,以避免遠程服務器由於活動中斷而丟失會話。

+0

好的,我已經添加了使KeepAlive適用於我的套接字的代碼。但是我現在期望的是什麼?當客戶端斷開連接時,什麼都不會發生......我希望在某處收到一個異常......我應該定期讀或寫一些東西嗎? – cedrou 2009-09-02 20:46:20

+1

我雖然在使用Begin/EndReceive?如果是這樣,則BeginReceive應該運行回調,並且當您調用EndReceive來獲取結果時應該引發異常,或讀取流0字節的末尾。 – 2009-09-02 22:51:54

+0

好吧,我現在得到一個異常...謝謝 – cedrou 2009-09-07 13:38:16

3

您可以使用下面的方法來查找客戶端是否仍然連接。這

public static bool IsConnected(this TcpClient client) 
{ 
    try 
    { 
     bool connected = !(client.Client.Poll(1, SelectMode.SelectRead) && client.Client.Available == 0); 

     return connected; 
    } 
    catch 
    { 
     return false; 
    } 
} 

answer是測試插座,這是我得到了我的代碼段。

+2

如果客戶端已經明確地關閉了連接,但是如果連接已經中斷(例如電纜拔出),這種方法可以正常工作。 – cedrou 2009-09-02 12:44:11

+0

哪裏是保持活着的地方,操作系統和TCP協議將處理定期消息給客戶端,看看它是否活着,並且輪詢套接字將檢查本地狀態。如果保持活動失敗,套接字應報告不再連接。 – 2009-09-02 15:01:08

+0

儘管在使用異步Begin/EndReceive時,不應要求輪詢,因爲當套接字未能保持活動狀態時,您應該收到具有錯誤的回調。 – 2009-09-02 15:01:55

0

你對客戶有控制嗎?如果是這樣,你不能讓客戶端發送一個特殊的數據包到服務器,說它正在斷開連接,然後斷開套接字?

您是否試圖檢測客戶端實際已斷開連接的情況(使用Socket.Shutdown()或Socket.Close())還是客戶端閒置了大量時間,因此需要被推出?

在這兩種情況下,讓客戶端向服務器發送一個定期的消息(就像你所做的那樣)。服務器可以跟蹤上一次檢測信號,如果客戶端錯過了超過3次檢測信號,則可以斷開客戶端連接。是的,它涉及額外的數據,但這在事物的宏偉計劃中並不算太壞。如果您調整它以便在足夠的時間內發送心跳信號,以便您瞭解客戶是否還活着,並且在心跳之間不要太長時間,那麼您可以擁有一個非常好的系統。