2015-08-25 48 views
0

我有一個tcp鏈接與服務器在Linux上的套接字。 我使用select()函數來監視是否有數據,如果有,我使用recv來獲取數據。tcp socket是否能注意到網絡破壞的異常?

現在我想知道網絡是否損壞(如電纜被移除)。 但即使監視異常,我也無法獲得例外。

FD_SET(m_socket, &except_fds); 

int result = select(m_socket + 1, &fds, 0, &except_fds, timeout == -1 ? 0 : &tv); 

什麼困惑我的是有類似的實現(java.net.Socket中)在Android,我可以馬上趕異常,如果我的手機設置爲飛行模式。

是select()實現平臺特定的?

總之,如果這種方法可以用來監測網絡的破損?如果沒有,有沒有解決方案?

回答

0

讓我困惑的是在android上有類似的實現(java.net.Socket),如果我將手機設置爲飛行模式,我可以立即捕獲異常。

不太相似。 java.net.Socket不使用select(),但在不支持SO_RCVTIMEO的平臺上讀取超時除外。

select()具體實現平臺嗎?

當然。

總之,如果這種方法可以用來監測網絡的破損?

如果沒有,有沒有這方面的任何解決方案?

您可以可靠地檢測到斷開的TCP連接的唯一方法是嘗試寫入它。最終,考慮到緩衝和重試,write()send()和朋友將返回-1與errno == ECONNRESET

0

您可能需要將套接字設置爲使用保持活動狀態,以便它能夠檢測連接是否已損壞。您將需要使用setsocketopt()SO_KEEPALIVE作爲第三個參數。嘗試檢查this了。

2

TCP協議通常工作的方式,錯誤是數據無法傳輸(不是ACK'd)。除非數據傳輸失敗,否則沒有錯誤。

因此,您可以使用setsockoptSO_KEEPALIVE定期發送小包來檢測丟失的連接,或者定義一個簡單的心跳協議。您也可以使用TCP_KEEPCNTTCP_KEEPIDLETCP_KEEPINTVL來覆蓋保持活動的默認值。

0

沒有什麼特別的你需要做。TCP連接的丟失,無論是由於另一端關閉還是由於錯誤,都不例外。您已經在等待套接字可讀,並且如果連接關閉或錯誤,您的等待就結束了。當等待結束時,您的代碼應該已經嘗試從套接字中讀取數據,所以它應該已經檢測到這種情況。

請注意,在大多數平臺上,連接暫時丟失將不會關閉TCP連接。這在臨時連接丟失的情況下會非常煩人。事實上,在過去,有些系統具有長期的TCP連接,但只有在有活動時才具有網絡連接。即使在故意禁用網絡連接的情況下,連接仍保持活動狀態。此行爲是設計使然。

檢測TCP鏈接是否仍然可用的最可靠方法是在其上發送數據。如果鏈接的另一端無法確認數據,發送將最終超時。 (您對發送功能的調用可能已經返回成功,但超時會觸發一個錯誤,使套接字可讀。當您調用讀取功能時,錯誤將會報告給您。)

0

如果您想要檢測網絡狀況的變化,您將需要使用特定的系統服務。

在較低級別,您可以使用udev中的規則檢測熱插拔或移除網絡設備。更高的服務就像NetworkManager,它將在DBUS上通信。您可以訂閱它以獲取網絡更改的通知。

如果您未使用NetworkManager,則取決於您的系統腳本。一些有ifdown-post和ifdown-local。其他人可以運行腳本來響應DHCP事件,其中包括拔掉網絡。其他人可以運行程序來監視網絡插頭狀態,如ifplug或ifplugd或netplugd。

如果您希望內核直接通知您而不是使用系統服務或守護進程,我認爲您需要使用netlink協議來掃描可用的網絡設備。

-1

select將在select正在監視的任何文件描述符上報告錯誤時返回。

對於套接字,如果操作系統失去與本地鏈路層網絡的連接,則會報告錯誤。這意味着如果主機完全丟失網絡連接,則返回select。這種情況發生在拔掉網線或將手機切換到飛行模式時。

然而,TCP並不知道遠程主機是否可達,所以如果遠程路由器關閉或遠程主機消失。您不太可能會收到錯誤,特別是當您沒有與遠程主機進行主動通信時,所以在連接超時之前,您將不會意識到任何問題。