如何從內(nèi)核角度看怎么設(shè)置connect超時(shí)?從這兩點(diǎn)入手
我們?cè)诰帉懢W(wǎng)絡(luò)程序時(shí),通常需要連接其他服務(wù)端(如微服務(wù)之間的通信),這時(shí)就需要通過調(diào)用 connect 函數(shù)來連接服務(wù)端。但我們發(fā)現(xiàn) connect 函數(shù)并沒有提供超時(shí)的設(shè)置,而在 Linux 系統(tǒng)中,connect 的默認(rèn)超時(shí)時(shí)間為75秒。所以,在連接不上服務(wù)端的情況下,我們需要等待75秒,這對(duì)我們不能接受的。
通過 SO_SNDTIMEO 設(shè)置 connect 超時(shí)時(shí)間
雖然 connect 系統(tǒng)調(diào)用沒有提供超時(shí)的設(shè)置,但我們通過查閱 Linux 內(nèi)核代碼可以發(fā)現(xiàn),connect 系統(tǒng)調(diào)用的超時(shí)時(shí)間可以通過 SO_SNDTIMEO 參數(shù)來設(shè)定的,而 SO_SNDTIMEO 參數(shù)可以通過 setsockopt 系統(tǒng)調(diào)用來設(shè)置,如下代碼:
一般來說,SO_SNDTIMEO 參數(shù)是用來設(shè)置 socket 的發(fā)送超時(shí)時(shí)間,為什么在 Linux 中還能設(shè)置 connect 的超時(shí)時(shí)間呢?我們來查看一下 connect 系統(tǒng)調(diào)用的實(shí)現(xiàn):
在 inet_stream_connect 函數(shù)中,首先調(diào)用了 sock_sndtimeo 獲取 socket 的 SO_SNDTIMEO 的值,我們來看看 sock_sndtimeo 函數(shù)的實(shí)現(xiàn):
sock_sndtimeo 函數(shù)只是簡(jiǎn)單的從 socket 對(duì)象中獲取 sndtimeo 字段的值,如果 socket 被設(shè)置了非阻塞,那么就返回0。
我們接著分析 inet_stream_connect 函數(shù),在獲取到 SO_SNDTIMEO 的值后,就調(diào)用 inet_wait_for_connect 函數(shù)等待 socket 連接返回。返回三種情況:
連接成功了。
連接超時(shí)了。
連接被中斷了。
如果連接成功,connect 會(huì)返回0;如果連接超時(shí),connect 會(huì)返回 EINPROGRESS 錯(cuò)誤;如果連接被中斷,connect 會(huì)返回 EINTR 錯(cuò)誤。
【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個(gè)人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦!?。∏?00名進(jìn)群領(lǐng)取,額外贈(zèng)送一份價(jià)值699的內(nèi)核資料包(含視頻教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)?


通過非阻塞與多路復(fù)用IO設(shè)置 connect 超時(shí)時(shí)間
從上面的分析可以看到,當(dāng)把 socket 設(shè)置為非阻塞時(shí),connect 系統(tǒng)調(diào)用會(huì)立刻返回 EINPROGRESS 錯(cuò)誤,這時(shí)我們可以把 socket 添加到多路復(fù)用 IO 中進(jìn)行監(jiān)聽,并且設(shè)置多路復(fù)用 IO 的超時(shí)時(shí)間即可達(dá)到設(shè)置 connect 超時(shí)時(shí)間的目的,如下代碼:
connect_timeout 函數(shù)實(shí)現(xiàn)了有超時(shí)機(jī)制的 connect,其主要步驟有:
通過調(diào)用 fcntl 函數(shù)把 socket 設(shè)置為非阻塞。
調(diào)用 connect 函數(shù)進(jìn)行連接服務(wù)端。
如果 connect 函數(shù)返回 EINPROGRESS 或者 EWOULDBLOCK 錯(cuò)誤,表示連接還沒有建立,所以此時(shí)把 socket 添加到選擇 中進(jìn)行監(jiān)聽,并且設(shè)置選擇 的超時(shí)時(shí)間。
判斷選擇 的返回值,如果返回值大于0,表示連接成功;如果返回值小于0,表示連接出錯(cuò);如果反正等于0,表示連接超時(shí)。
最后把 socket 恢復(fù)到阻塞模式。
這種設(shè)置 connect 的超時(shí)時(shí)間的方式比前面設(shè)置 SO_SNDTIMEO 值的方式更為通用,因?yàn)樵诜?Linux 系統(tǒng)中,設(shè)置 SO_SNDTIMEO 值的方式不一定有效。
