這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
英文原文:Using TCP keepalive with Go
如果你寫過某些 TCP socket 代碼,你可能會疑問:如果網線被撥掉或者遠程主機崩潰了我的TCP串連會怎樣? 簡短的答案是:一點影響都沒有。這種情況下串連的結束遠程主機是不會發送FIN資料包的,並且本地系統不能檢測串連是否已中止。所以需要作為程式員的你來解決這種情況。 |
--zxp 翻譯於 1 個月 前 0人頂 頂 翻譯的不錯哦! |
GO語言為你提供瞭解決這個問題的幾種方法。首選的方法可能是 net.Conn 介面中的SetReadDeadline方法。假設你的串連在以一種特定的間隔來接收資料,你可以簡單地把讀取逾時當作一個io.EOF錯誤並Close這個串連。很多現有的TCP協議都支援處理錯誤的這種方法,它們通過定義某種心跳機制或 service health 1,在端點間以特定間隔發送PING/PONG探測包來檢測雙方網路問題。另外,這種心跳機制也可能有助於Proxy 伺服器查看網路活動來決定串連的健康品質。 |
--zxp 翻譯於 1 個月 前 0人頂 頂 翻譯的不錯哦! |
所以,如果你的協議支援心跳的話,或者你能夠為自己的協議加入心跳的話,這個方案應該是解決網路掉線問題的首選。 但是,如果你對該協議沒有控制權並且它也不支援心跳你該怎麼辦? 現在是時候該瞭解 TCP keepalive並在GO中使用它了。TCP keepalive定義於RFC 1122,但並不是TCP規範中的一部分。它可以在個別的串連中啟用,但預設必需是關閉的。啟用它會使網路棧在空閑了特定時間後(不能低於2小時)探測串連的串連狀況。探測包不能包含資料2,並且一個探測包的回複的失敗不能將串連看作已中止,因為探測包的傳輸是不可靠的。 |
--zxp 翻譯於 1 個月 前 0人頂 頂 翻譯的不錯哦! |
GO 可以通過 net.TCPConn 的 SetKeepAlive 來啟用 TCP keepalive。在 OS X 和 Linux 系統上,當一個串連空間了2個小時時,會以75秒的間隔發送8個TCP keepalive探測包。換句話說, 在兩小時10分鐘後(7200+8*75)Read將會返回一個 io.EOF 錯誤. 對於你的應用,這個逾時間隔可能太長了。在這種情況下你可以調用SetKeepAlivePeriod方法。但這個方法在不同的作業系統上會有不同的表現。在OSX上它會更改發送探測包前串連的空間時間。在Linux上它會更改串連的空間時間與探測包的發送間隔。所以以30秒的參數調用 SetKeepAlivePeriod在OSX系統上會導致共10分30秒(30+8*75)的逾時時間,但在linux上卻是4分30秒(30+8*30). |
--zxp 翻譯於 1 個月 前 0人頂 頂 翻譯的不錯哦! |
我發現這種情況令人十分不滿意,所以我建立了一個包,名叫tcpkeepalive,用來提供給你更多的控制: kaConn, _ := tcpkeepalive.EnableKeepAlive(conn)kaConn.SetKeepAliveIdle(30*time.Second)kaConn.SetKeepAliveCount(4)kaConn.SetKeepAliveInterval(5*time.Second) 目前,僅支援Linux和OS X,但是我很樂意將其他平台上的pull requests合并。如果Go核心團隊的成員對此感興趣,我也願意嘗試將這些新方法貢獻給Go本身。 請讓我知道你是否覺得這篇文章有價值,如果有任何疑問,請指出;並請指出任何錯誤,以便我可以進行更正。
|
0x0bject 翻譯於 1 個月 前 0人頂 頂 翻譯的不錯哦! |
附錄 1)早期通過一個較低,並且不真實的檢出率來調優一個心跳機制故障,是件棘手的事情。可以檢出 ϕ Accrual Failure Detector 來擷取一個統計模型,同樣也可以用 Damian Gryski 的 go-failure 擴充。可惜的是,我想不到有什麼辦法可以在保活機制中使用它。 2)根據 RFC 1122 keepalive 分節,可能在零碎實現的相容性中存在單個垃圾八位元。然而,我不確定是不是被系統網路堆棧過濾掉了,如果你知道,請在下面發評論留言。 |
0x0bject 翻譯於 1 個月 前 0人頂 頂 翻譯的不錯哦! |
本文中的所有譯文僅用於學習和交流目的,轉載請務必註明文章譯者、出處、和本文連結
我們的翻譯工作遵照 CC 協議,如果我們的工作有侵犯到您的權益,請及時聯絡我們