TCP/IP学习笔记(五)TCP的保活定时器
正常情況下,TCP連接的終止需要經(jīng)歷四次揮手階段,體現(xiàn)在代碼上就是某一端主動調(diào)用close函數(shù)關(guān)閉套接字,隨后TCP向?qū)Χ税l(fā)送FIN位被置為1的報(bào)文段標(biāo)志著連接的結(jié)束,同時對端響應(yīng)應(yīng)答報(bào)文段,并在隨后的某一時刻同樣調(diào)用close函數(shù),發(fā)送FIN報(bào)文段,當(dāng)確認(rèn)完成后就標(biāo)志著TCP連接正常終止。
然而,考慮一種情況,在TCP連接建立成功后,客戶端主機(jī)突然崩潰(斷電,斷網(wǎng)等),導(dǎo)致客戶端的TCP還沒來得及將FIN發(fā)送給服務(wù)器就已經(jīng)關(guān)閉了(或者由于斷網(wǎng)導(dǎo)致FIN無法到達(dá)對端),而服務(wù)器通常又不會主動發(fā)送數(shù)據(jù)給客戶端。在這種情況下,客戶端已經(jīng)關(guān)閉,服務(wù)器卻不知道,依然保持著維護(hù)一個連接應(yīng)該有的所有東西(包括文件描述符,TCP緩沖區(qū)等),一個還好,當(dāng)有大量這種半開連接存在于服務(wù)器中,會造成大量的浪費(fèi)
保活定時器
在TCP協(xié)議中,有一個被稱作保活定時器的組件,它就是為了解決上述問題被引進(jìn)的。該定時器的原理也非常簡單,當(dāng)通信雙方在定時器規(guī)定的這段時間內(nèi)沒有進(jìn)行數(shù)據(jù)交互,那么開啟保活選項(xiàng)的一端TCP就會發(fā)送一個探查報(bào)文段,當(dāng)對端TCP接收到報(bào)文段發(fā)現(xiàn)這是個探查報(bào)文時,會響應(yīng)應(yīng)答信息。
上述過程是TCP獨(dú)立于應(yīng)用程序進(jìn)行的,應(yīng)用程序不會知道探查報(bào)文的發(fā)送和到達(dá)
此外,保活定時器的定時時間是兩小時,是系統(tǒng)級別的參數(shù),可以更改,但是最好不要更改,會影響到系統(tǒng)進(jìn)程
如果一個連接在兩小時內(nèi)沒有任何數(shù)據(jù)交互,則服務(wù)器就向客戶端發(fā)送一個探查報(bào)文段(假設(shè)服務(wù)器開啟保活定時器),此時客戶端主機(jī)有四中可能的狀態(tài)
- 客戶端主機(jī)依然正常運(yùn)行,并從服務(wù)器可達(dá)。客戶端TCP接收到探查報(bào)文段并返回應(yīng)答報(bào)文段,此時服務(wù)器知道客戶端依然存在,所以重置保活定時器。另外,如果在定時器溢出之前進(jìn)行了數(shù)據(jù)交互,定時器也會被重置
- 客戶端主機(jī)已崩潰,已關(guān)閉或者正在重啟。這種情況下,服務(wù)器無法得到客戶端回應(yīng),探測報(bào)文段在75秒后超時,服務(wù)器總共發(fā)送10個這樣的探測,每個間隔75秒(超時重傳)。如果服務(wù)器還是沒有接收到客戶端的應(yīng)答,就認(rèn)為客戶端已經(jīng)關(guān)閉,隨后告知應(yīng)用程序,關(guān)閉連接(套接字變?yōu)榭勺x,讀取錯誤信息為“連接超時”)
- 客戶端主機(jī)崩潰并已重啟。在這種情況下,由于客戶端重啟了系統(tǒng),所有的TCP連接信息都已經(jīng)丟失,當(dāng)接收到服務(wù)器的探測報(bào)文段時,客戶端在本機(jī)中無法找到匹配的TCP連接,隨后發(fā)送一個復(fù)位報(bào)文段,服務(wù)器接收到復(fù)位報(bào)文段后告知應(yīng)用程序,關(guān)閉連接(套接字變?yōu)榭勺x,讀取錯誤信息為“連接被重置”)
- 客戶端主機(jī)正常運(yùn)行,但是從服務(wù)器不可達(dá)。這種情況通常是由于傳輸路徑中的某個路由器關(guān)閉導(dǎo)致,此種情況與客戶端主機(jī)崩潰并正在重啟時處理方式相同,因?yàn)槎际鞘詹坏綉?yīng)答
下面通過tcpdump抓包分析后三種情況,分析時假設(shè)崩潰的一方是服務(wù)器,隨后觀察客戶端TCP探查報(bào)文段發(fā)送情況
另一端主機(jī)崩潰,已關(guān)閉或正在重啟
借用<TCP/IP詳解>中的示例,建立TCP連接后等待四小時后斷開服務(wù)器以太網(wǎng)電纜,觀察客戶端探查報(bào)文段發(fā)送情況
觀察tcpdump輸出結(jié)果(省略了三次握手的報(bào)文段)
結(jié)果中前三行表示客戶端發(fā)送”hello world”報(bào)文段,服務(wù)器對該報(bào)文段進(jìn)行應(yīng)答并回顯”hello world”報(bào)文段,客戶端對服務(wù)器的報(bào)文段進(jìn)行應(yīng)答
隨后的四小時內(nèi),客戶端先后兩次嘗試探查服務(wù)器是否關(guān)閉,首先看到的是一個ARP請求和ARP應(yīng)答,隨后發(fā)送探查報(bào)文段并得到回應(yīng)
接下來斷開服務(wù)器以太網(wǎng)電纜,并在兩個小時之后又進(jìn)行探查,然而由于服務(wù)器主機(jī)以太網(wǎng)斷開,無法回應(yīng)客戶端ARP請求,隨后的每75秒進(jìn)行一次超時重傳,最終放棄,錯誤碼為“連接超時”
ARP請求主要用來獲取對端的物理地址,首先需要知道對方地址,才能發(fā)送數(shù)據(jù),而由于服務(wù)器以太網(wǎng)斷開無法回應(yīng)ARP請求,所以上述過程沒有看到TCP報(bào)文的發(fā)送就已經(jīng)可以確認(rèn)對方崩潰
另一端崩潰并重新啟動
借用<TCP/IP詳解>中的示例,在建立連接后將服務(wù)器以太網(wǎng)斷開,重新啟動,然后再連接到網(wǎng)絡(luò)上。由于服務(wù)器已重啟,對于之前所有的TCP連接信息都已丟失,當(dāng)接收到客戶端發(fā)來的探查報(bào)文段時,會回復(fù)一個復(fù)位報(bào)文段
觀察tcpdump輸出結(jié)果(省去了連接建立過程)
可以看到,由于服務(wù)器以太網(wǎng)連接正常,ARP請求得到應(yīng)答,隨后客戶端發(fā)送探查報(bào)文段,但是服務(wù)器已經(jīng)重啟,沒有關(guān)于該連接的信息,只能返回一個復(fù)位報(bào)文段
另一端不可達(dá)
再次使用<TCP/IP詳解>中的示例,連接建立后先確認(rèn)可以正常通訊,等待兩小時后發(fā)送探查報(bào)文并收到回應(yīng),隨后將中間鏈路斷開,觀察結(jié)果
觀察tcpdump輸出結(jié)果(省略掉連接的建立過程)
前三行是正常的回顯流程,4,5行是兩小時后的探查報(bào)文,隨后的若干行由于中間鏈路被斷開,引發(fā)來自客戶端主機(jī)路由器的ICMP不可達(dá)錯誤,隨后又連續(xù)發(fā)送了9個探查報(bào)文,最終返回給應(yīng)用程序“沒有到達(dá)主機(jī)的路由”錯誤
SO_KEEPALIVE選項(xiàng)
linux內(nèi)核中有關(guān)于保活定時器的三個參數(shù)
- tcp_keepalive_time,指空閑時長,tcp_keepalive_time時間沒有數(shù)據(jù)交互就發(fā)送探查報(bào)文段,默認(rèn)7200s(2h)
- tcp_keepalive_intvl,發(fā)送探查報(bào)文段后如果沒有收到應(yīng)答,tcp_keepalive_intvl時間后會重新發(fā)送,默認(rèn)是75s
- tcp_keepalive_probes,發(fā)送探查報(bào)文沒有收到應(yīng)答后繼續(xù)發(fā)送的次數(shù),發(fā)送tcp_keepalive_probes次后認(rèn)為對方已關(guān)閉,默認(rèn)是9次
如果要更改,可以在/etc/sysctl.conf文件中寫入(值自己設(shè)置)
net.ipv4.tcp_keepalive_time = net.ipv4.tcp_keepalive_probes = net.ipv4.tcp_keepalive_intvl =保存后執(zhí)行sysctl -p生效。這里是直接修改了內(nèi)核參數(shù),此后所有的進(jìn)程的SO_KEEPALIVE時間都被更改
但是由于上述三個參數(shù)都是系統(tǒng)級別的參數(shù),也就是說如果更改,那么就會影響開啟了SO_KEEPALIVE的系統(tǒng)進(jìn)程,可能造成意想不到的后果
如果只想在某個應(yīng)用程序中修改時間,除了開啟SO_KEEPALIVE選項(xiàng)外,需要同時設(shè)計(jì)三個TCP參數(shù)
#include <netinet/tcp.h>/* fd : 套接字描述符* time : 空閑時間,當(dāng)time時間沒有數(shù)據(jù)交互的話就發(fā)送探查報(bào)文 */ int enableKeepAlive(int fd, int time) {int val = 1;::setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));val = time; //空閑時間::setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val));val = time / 3; //探查報(bào)文的發(fā)送間隔::setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val));val = 3; //探查報(bào)文的發(fā)送次數(shù)::setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)); }總結(jié)
以上是生活随笔為你收集整理的TCP/IP学习笔记(五)TCP的保活定时器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TCP/IP学习笔记(四)TCP超时重传
- 下一篇: 每天一道LeetCode-----寻找给