Go語言中怎么開啟TCPkeepalive

這篇文章將為大家詳細講解有關(guān)Go語言中怎么開啟TCPkeepalive,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。

創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于網(wǎng)站設(shè)計、成都網(wǎng)站設(shè)計、嘉祥網(wǎng)絡(luò)推廣、微信小程序開發(fā)、嘉祥網(wǎng)絡(luò)營銷、嘉祥企業(yè)策劃、嘉祥品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運營等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們最大的嘉獎;創(chuàng)新互聯(lián)公司為所有大學(xué)生創(chuàng)業(yè)者提供嘉祥建站搭建服務(wù),24小時服務(wù)熱線:18980820575,官方網(wǎng)址:bm7419.com

TCP-keepalive — 一個輕量級的 ping

TCP keepalive發(fā)送沒有(或者幾乎沒有)包體負載的 TCP 報文給對端,并且對端會回復(fù) keepaliveACK確認包。它不是 TCP 標準的一部分(盡管在RFC1122[3]中有相關(guān)的描述),并且,它總是默認被禁用。盡管如此,大部分現(xiàn)代的 TCP 協(xié)議棧都支持這個特性。

在它的大部分實現(xiàn)中,簡單來說,有三個主要參數(shù):

Idle time(空閑時間) - 接收一個包后,等待多長時間發(fā)出一個 ping 包。Retry interval(重試間隔時間) - 如果發(fā)送了一個 ping,但是沒有收到對端回復(fù)的ACK,在重試間隔時間之后重新發(fā)送 ping。Ping amount(重試次數(shù)) - 重試次數(shù)(沒有收到對端ACK)達到多少次后,我們認為這個連接不存活了。

舉個例子,空閑時間是 30 秒,重試間隔時間是 5 秒,重試次數(shù)為 3。以下是它的工作方式:

服務(wù)端收到客戶端的一包應(yīng)用層數(shù)據(jù)。然后客戶端不再發(fā)送任何數(shù)據(jù)。服務(wù)端等待 30 秒。然后發(fā)送一個 ping 給客戶端。如果服務(wù)端收到了ACK,則服務(wù)端等待另一個 30 秒,再次發(fā)送 ping;如果在這 30 秒內(nèi)服務(wù)端收到了數(shù)據(jù),則 30 秒的定時器被重置。

如果服務(wù)端沒有收到ACK,等待 5 秒后再次發(fā)送 ping。如果再過 5 秒還是沒有收到回復(fù)?發(fā)送最后一個 ping 并等待最后一個 5 秒(是的,在最后一個 ping 也需要等待重試間隔時間)。然后我們認為這個連接超時了并且在服務(wù)端斷開它。

默認值

據(jù)說 Window 系統(tǒng)在發(fā)送 keepalive ping 之前默認等待 2 小時。Linux 下獲取默認值十分簡單,就像此處 3.1.1 節(jié)[4]描述的這樣。

# Idle timecat /proc/sys/net/ipv4/tcp_keepalive_time# Retry intervalcat /proc/sys/net/ipv4/tcp_keepalive_intvl# Ping amountcat /proc/sys/net/ipv4/tcp_keepalive_probes

在 Go 語言中如何設(shè)置?

由于我最近使用 Go 語言比較多,我需要在 Go 語言中運用 TCP keepalive。

討論開始之前需要說明,以下內(nèi)容適用于 Linux。我不是百分百確定它是否適用于 OSX,但我?guī)缀蹩梢钥隙ㄋ贿m用于 Windows。

連接的特殊類型

首先,我注意到我在服務(wù)端程序中只使用了net.Conn[5]類型。但是它并不管用,它缺少我們需要的特定方法。我們需要TCPConn[6]類型。

這意味著,我們需要使用ListenTCP[7]和AcceptTCP[8]而不是Listen[9]和Accept[10](它們的調(diào)用方式有區(qū)別,ListenTCP使用結(jié)構(gòu)體而不是字符串來表示地址。我們調(diào)用方式大概會像這樣:ListenTCP("tcp", &net.TCPAddr{Port: myClientPort})。如果你不特別指定的話,IP 的默認值為0.0.0.0)。之后它會返回我們需要的類型TCPConn。

Go 語言提供的方法

如果你翻看文檔可能會注意到這兩個相關(guān)的方法:SetKeepAlive[11]和SetKeepAlivePeriod[12]。func (c *TCPConn) SetKeepAlive(keepalive bool) error的調(diào)用方式十分簡單:傳入true從而打開 TCP keepalive 機制。

但是接下來的func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error就有些令人困惑了。我們用它究竟設(shè)置的是什么?答案可以在這篇文章[13](好文章,推薦閱讀)中找到:它同時設(shè)置了空閑時間重試間隔時間。而重試間隔次數(shù)則使用系統(tǒng)的默認值。所以如果我設(shè)置5 * time.Second。那么它可能是等待 5 秒鐘,發(fā)送 ping 并等待另一個 5 秒。并且 8 次重試(取決于系統(tǒng)設(shè)置)。而我需要更大的靈活性,設(shè)置得更精準。

進入系統(tǒng)層面

可以通過直接操作 socket 參數(shù)來實現(xiàn)。我沒有關(guān)注里面太多的細節(jié),這純粹是我的個人解釋。以下是我們?nèi)绾卧O(shè)置空閑時間為 30 秒(我們可以通過SetKeepAlivePeriod設(shè)置,因為其他參數(shù)我們再另外設(shè)置),重試時間間隔設(shè)置為 5 秒,重試次數(shù)設(shè)置為 3。我偷了(啊呸,是參考了)上面所引用的文章中的一些代碼,多謝。

conn.SetKeepAlive(true)conn.SetKeepAlivePeriod(time.Second * 30) // Getting the file handle of the socket sockFile, sockErr := conn.File() if sockErr == nil { // got socket file handle. Getting descriptor. fd := int(sockFile.Fd()) // Ping amount err := syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPCNT, 3) if err != nil {        Warning("on setting keepalive probe count", err.Error())    } // Retry interval err = syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, 5) if err != nil {        Warning("on setting keepalive retry interval", err.Error())    } // don't forget to close the file. No worries, it will *not* cause the connection to close. sockFile.Close()} else {    Warning("on setting socket keepalive", sockErr.Error())}

在這段代碼之后的某一行我會寫上dataLength, err := conn.Read(readBuf),這行代碼會阻塞直到收到數(shù)據(jù)或者發(fā)生錯誤。如果是 keepalive 引起的錯誤,err.Error()將會包含連接超時信息。

關(guān)于文件描述符的坑

上面的代碼只有在你不頻繁調(diào)用的前提下才運行良好。在寫完這篇文章之后,我以困難模式學(xué)習到了一個關(guān)于它的小問題。。。

問題就隱藏在Fd[14]函數(shù)調(diào)用。我們來看它的實現(xiàn)。

func (f *File) Fd() uintptr { if f == nil { return ^(uintptr(0))    } // If we put the file descriptor into nonblocking mode, // then set it to blocking mode before we return it, // because historically we have always returned a descriptor // opened in blocking mode. The File will continue to work, // but any blocking operation will tie up a thread. if f.nonblock {        f.pfd.SetBlocking()    } return uintptr(f.pfd.Sysfd)}

如果文件描述符處于非阻塞模式,會將它修改為阻塞模式。根據(jù)stackoverflow 的這個回答[15],舉例來說,當 Go 增加一個阻塞的系統(tǒng)調(diào)用,運行時調(diào)度器將該系統(tǒng)調(diào)用所屬協(xié)程所屬系統(tǒng)線程從調(diào)度池中移出。如果調(diào)度池中的系統(tǒng)線程數(shù)小于GOMAXPROCS,則會創(chuàng)建新的系統(tǒng)線程。鑒于我的每一個連接都使用一個獨立協(xié)程,你可以想象一下這個爆炸速度。將很快到達 10000 線程的限制然后 panic。

將它放入獨立協(xié)程并不好使。

但是有一個方法是可行的。注意,前提是 Go 版本高于 1.11??匆韵麓a。

//Sets additional keepalive parameters. //Uses new interfaces introduced in Go1.11, which let us get connection's file descriptor, //without blocking, and therefore without uncontrolled spawning of threads (not goroutines, actual threads). func setKeepaliveParameters(conn devconn) {    rawConn, err := conn.SyscallConn() if err != nil {        Warning("on getting raw connection object for keepalive parameter setting", err.Error())    }    rawConn.Control( func(fdPtr uintptr) { // got socket file descriptor. Setting parameters. fd := int(fdPtr) //Number of probes. err := syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPCNT, 3) if err != nil {                Warning("on setting keepalive probe count", err.Error())            } //Wait time after an unsuccessful probe. err = syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, 3) if err != nil {                Warning("on setting keepalive retry interval", err.Error())            }        })} func deviceProcessor(conn devconn) { //............ conn.SetKeepAlive(true)    conn.SetKeepAlivePeriod(time.Second * 30)    setKeepaliveParameters(conn) //............ dataLen, err := conn.Read(readBuf) //............ }

最新版本的 Go 提供了一些新接口,net.TCPConn實現(xiàn)了SyscallConn[16],它使得你可以獲取RawConn[17]對象從而設(shè)置參數(shù)。你所需要做的就是定義一個函數(shù)(就像上面例子中的匿名函數(shù)),它接收一個指向文件描述符的參數(shù)。這是操作連接中的文件描述符而不造成阻塞調(diào)用的方法,可避免出現(xiàn)瘋狂創(chuàng)建線程的情況。

關(guān)于Go語言中怎么開啟TCPkeepalive就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

網(wǎng)站標題:Go語言中怎么開啟TCPkeepalive
分享網(wǎng)址:http://bm7419.com/article14/ggoode.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護、手機網(wǎng)站建設(shè)、建站公司網(wǎng)站改版、動態(tài)網(wǎng)站、ChatGPT

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運營