歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Go 語言使用 TCP keepalive

Go 語言使用 TCP keepalive

日期:2017/3/1 9:38:27   编辑:Linux編程

如果你寫過某些 TCP socket 代碼,你可能會疑問:如果網線被撥掉或者遠程主機崩潰了我的TCP連接會怎樣?

簡短的答案是:一點影響都沒有。這種情況下連接的結束遠程主機是不會發送FIN數據包的,並且本地系統不能檢測連接是否已中斷。所以需要作為程序員的你來解決這種情況。

GO語言為你提供了解決這個問題的幾種方法。首選的方法可能是 net.Conn 接口中的SetReadDeadline方法。假設你的連接在以一種特定的間隔來接收數據,你可以簡單地把讀取超時當作一個io.EOF錯誤並Close這個連接。很多現有的TCP協議都支持處理錯誤的這種方法,它們通過定義某種心跳機制或 service health 1,在端點間以特定間隔發送PING/PONG探測包來檢測雙方網絡問題。另外,這種心跳機制也可能有助於代理服務器查看網絡活動來決定連接的健康質量。

所以,如果你的協議支持心跳的話,或者你能夠為自己的協議加入心跳的話,這個方案應該是解決網絡掉線問題的首選。

但是,如果你對該協議沒有控制權並且它也不支持心跳你該怎麼辦?

現在是時候該了解 TCP keepalive並在GO中使用它了。TCP keepalive定義於RFC 1122,但並不是TCP規范中的一部分。它可以在個別的連接中啟用,但默認必需是關閉的。啟用它會使網絡棧在空閒了特定時間後(不能低於2小時)探測連接的連接狀況。探測包不能包含數據2,並且一個探測包的回復的失敗不能將連接看作已中斷,因為探測包的傳輸是不可靠的。

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).

我發現這種情況令人十分不滿意,所以我創建了一個包,名叫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本身。

請讓我知道你是否覺得這篇文章有價值,如果有任何疑問,請指出;並請指出任何錯誤,以便我可以進行更正。

附錄

1)早期通過一個較低,並且不真實的檢出率來調優一個心跳機制故障,是件棘手的事情。可以檢出 ϕ Accrual Failure Detector 來獲取一個統計模型,同樣也可以用 Damian Gryski 的 go-failure 擴展。可惜的是,我想不到有什麼辦法可以在保活機制中使用它。

2)根據 RFC 1122 keepalive 分節,可能在零碎實現的兼容性中存在單個垃圾八進制數。然而,我不確定是不是被系統網絡堆棧過濾掉了,如果你知道,請在下面發評論留言。

英文原文:Using TCP keepalive with Go

Ubuntu 安裝Go語言包 http://www.linuxidc.com/Linux/2013-05/85171.htm

《Go語言編程》高清完整版電子書 http://www.linuxidc.com/Linux/2013-05/84709.htm

Go語言並行之美 -- 超越 “Hello World” http://www.linuxidc.com/Linux/2013-05/83697.htm

我為什麼喜歡Go語言 http://www.linuxidc.com/Linux/2013-05/84060.htm

Go語言內存分配器的實現 http://www.linuxidc.com/Linux/2014-01/94766.htm

Go語言的國際化支持(基於gettext-go) http://www.linuxidc.com/Linux/2014-01/94917.htm

Copyright © Linux教程網 All Rights Reserved