[英]Detecting disconnected client side socket connection (cross-platform applicability)
我知道這個問題有數百個答案,但就我的情況而言,我無法解決。 場景是這樣的,我們有一個用TCP / IP協議編寫的服務器,我們有多個客戶端連接到該服務器。 客戶端是一個軟件模塊,在客戶端計算機上啟動之前,該模塊在服務器中注冊其存在並加載功能。 但是問題在於,這個軟件模塊崩潰了,並且沒有調用socket.close()
,即使它崩潰了,這也會使其足跡仍然存在於服務器中。 如何識別呢?
我正在客戶端中使用select()
方法來通知來自客戶端和服務器的任何信息(反之亦然)我無法為服務器中的每個客戶端請求分別創建進程,也無法在客戶端計算機中創建父子機制。 tcp-keepalive
不適用,因為我們需要在Windows中調整注冊表? 我需要一個x平台兼容的解決方案。 我已經閱讀到服務器代碼中連接套接字的recv()
將從“那個”客戶端返回一些值,例如0
表示套接字已關閉? 我可以使用它清除服務器數據庫中的客戶端套接字注冊嗎? 這樣行嗎?
您沒有在服務器端代碼中指定用於處理套接字事件的方法。 無論對於輪詢方法的插槽,你正在使用recv()
返回0或可能 -1 / SOCKET_ERROR
當客戶端崩潰。
為了檢測不活動的客戶端連接,大多數服務器應用程序會在應用程序層協議內定期發出某種形式的心跳或ping消息。 當從客戶端發送ACK失敗時,服務器應用程序將通過以下方式recv()
通知:客戶端通過recv()
返回0或SOCKET_ERROR
斷開連接,錯誤代碼類似於WSAENETRESET
, WSAECONNABORTED
, WSAETIMEDOUT
或WSAECONNRESET
(請參見此處的各種錯誤代碼) )。 通常,在服務器將檢測信號發送到不再活動的客戶端TCP端口后,會發送ICMP數據包作為響應,這將警告您服務器該端口或主機未活動( recv()
會立即通知您此事件)。
如果希望打開TCP保持活動計時器,則可以使用套接字選項SO_KEEPALIVE 。 也可以使用SIO_KEEPALIVE_VALS設置間隔。
編輯:請記住各種錯誤代碼和選項SIO_KEEPALIVE_VALS是Win32特定的。 要為其他操作系統處理這些事件,您將需要使用特定的操作方式來檢索錯誤代碼並設置TCP保持活動間隔(如果選擇這樣做)。 關於使代碼跨平台兼容的最佳建議是,將簡單的應用程序層心跳消息實施到協議或某些其他應用程序特定的超時中。 這樣做會使您忘記管理TCP保持活動。
我無法評論EJP的答案,但必須指出,通過調用send()
他有效地建議您在協議的應用程序層中實現心跳/ ping消息。 雖然檢查send()
的返回值很重要,但如果您輪詢/選擇讀取事件,則在調用recv()
,TCP棧認為連接斷開時,會立即通知您TCP連接被斷開。 如果您等待應用程序計時器嘗試使用send()
發送一些數據,則在recv()
已經通知您連接斷開后,可能要花費幾秒鍾(取決於間隔計時器的長度)。 換句話說:注意recv()
返回值以及send()
返回值。
tcp-keepalive
不適用,因為我們需要在Windows中調整注冊表?
如果您可以接受默認的兩個小時超時,則可以使用TCP keepalive。
我需要一個x平台兼容的解決方案。
TCP keepalive是跨平台的。
我已經閱讀到服務器代碼中連接套接字的
recv()
將從“那個”客戶端返回一些值,例如0
表示套接字已關閉?
如果對等方關閉其套接字,它將返回零;在某些平台上,如果對等進程僅退出而不關閉它,則將返回零。
我可以使用它清除服務器數據庫中的客戶端套接字注冊嗎? 這樣行嗎?
僅當您可以依靠對等端正確關閉套接字時。
在我看來,您應該做的是調試客戶端代碼,使其不會崩潰,並使用TCP keepalive作為長期備份。
您還應該知道, send()
到已退出對等方的send()
遲早會失敗,並出現ECONNRESET錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.