通過(guò)實(shí)踐帶你揭開(kāi)TCP中CLOSE_WAIT和TIME_WAIT的神秘面紗

linux服務(wù)器開(kāi)發(fā)相關(guān)視頻解析:

10道經(jīng)典面試題的剖析琐簇, 技術(shù)方向如何決定職業(yè)方向

linux多線(xiàn)程之epoll原理剖析與reactor原理及應(yīng)用

c/c++ linux服務(wù)器開(kāi)發(fā)免費(fèi)學(xué)習(xí)地址:c/c++ linux后臺(tái)服務(wù)器高級(jí)架構(gòu)師

CLOSE_WAIT和TIME_WAIT是如何產(chǎn)生的埋酬?大量的CLOSE_WAIT和TIME_WAIT又有何隱患麻裳?本文將通過(guò)實(shí)踐角度來(lái)帶你揭開(kāi)CLOSE_WAIT和TIME_WAIT的神秘面紗壕探!遇事不決先祭此圖:

稍微補(bǔ)充一點(diǎn):TIME_WAIT到CLOSED,這一步是超時(shí)自動(dòng)遷移狞甚。

兩條豎線(xiàn)分別是表示:

1等曼、主動(dòng)關(guān)閉(active close)的一方

2、被動(dòng)關(guān)閉(passive close)的一方

網(wǎng)絡(luò)上類(lèi)似的圖有很多损离,但是有的細(xì)節(jié)不夠哥艇,有的存在誤導(dǎo)。有的會(huì)把兩條線(xiàn)分別標(biāo)記成Client和Server僻澎。給讀者造成困惑貌踏。對(duì)于斷開(kāi)連接這件事十饥,客戶(hù)端和服務(wù)端都能作為主動(dòng)方發(fā)起,也就是「主動(dòng)關(guān)閉」可以是客戶(hù)端祖乳,可以是服務(wù)端逗堵。而對(duì)端相應(yīng)的就是「被動(dòng)關(guān)閉」。不管誰(shuí)發(fā)起眷昆,狀態(tài)遷移如上圖蜒秤。

1. 耗盡的是誰(shuí)的端口?

首先解答初學(xué)者對(duì)socket的認(rèn)識(shí)存在一個(gè)常見(jiàn)的誤區(qū)亚斋。作為服務(wù)端作媚,不管哪個(gè)WAIT都不會(huì)耗盡客戶(hù)端的端口!

舉個(gè)例子伞访,我在某云的云主機(jī)上有個(gè)Server程序:echo_server掂骏。我啟動(dòng)它,監(jiān)聽(tīng)2605端口厚掷。然后我在自己的MacBook上用telnet去連接它弟灼。連上之后,在云主機(jī)上用 netstat -anp看一下:

[guodong@yun test] netstat -anp|grep2 605

tcp 000.0.0.0:26050.0.0.0:*LISTEN3354/./echo_server

tcp 0172.12.0.2:2605xx.xx.xx.xx:31559ESTABLISHED3354/./echo_server

xx.xx.xx.xx是我Macbook的本機(jī)IP

其中有兩條記錄冒黑,LISTEN的表示是我的echo_server監(jiān)聽(tīng)一個(gè)端口田绑。ESTABLISHED表示已經(jīng)有一個(gè)客戶(hù)端連接了。第三列的IP端口是我echo_server的(這個(gè)顯示IP是局域網(wǎng)的抡爹;第四列顯示的是客戶(hù)端的IP和端口掩驱,也就是我MacBook。

要說(shuō)明的是這個(gè)端口:31559是客戶(hù)端的冬竟。這個(gè)是建立連接時(shí)的MacBook分配的隨機(jī)端口欧穴。

我們看一下echo_server占用的fd。使用 ls /proc/3354/fd -l 命令查看泵殴,其中 3354是echo_server的pid:

0->?/dev/pts/6

1->?/dev/pts/6

2->?/dev/pts/6

3->?anon_inode:[eventpoll]

4->?socket:[674802865]

5->?socket:[674804942]

0涮帘,1,2是三巨頭(標(biāo)準(zhǔn)輸入笑诅,輸出调缨,錯(cuò)誤)自不必言。3是因?yàn)槲沂褂昧薳poll吆你,所以有一個(gè)epfd弦叶。

4其實(shí)就是我服務(wù)端監(jiān)聽(tīng)端口打開(kāi)的被動(dòng)套接字;

5就是客戶(hù)端建立連接到時(shí)候妇多,分配給客戶(hù)端的連接套接字伤哺。server程序只要給5這個(gè)fd寫(xiě)數(shù)據(jù),就相當(dāng)于返回?cái)?shù)據(jù)給客戶(hù)端砌梆。

服務(wù)端怎么會(huì)耗盡客戶(hù)端的端口號(hào)的默责。這里消耗的其實(shí)是服務(wù)端的fd(也不是端口)贬循!

【文章福利】需要C/C++ Linux服務(wù)器架構(gòu)師學(xué)習(xí)資料加群812855908(資料包括C/C++咸包,Linux桃序,golang技術(shù),Nginx烂瘫,ZeroMQ媒熊,MySQL,Redis坟比,fastdfs芦鳍,MongoDB,ZK葛账,流媒體柠衅,CDN,P2P籍琳,K8S菲宴,Docker,TCP/IP趋急,協(xié)程喝峦,DPDK,ffmpeg等)


2. 什么時(shí)候出現(xiàn)CLOSE_WAIT?

2.1 舉個(gè)例子

回到我的MacBook終端呜达,查看一下2605有關(guān)的連接(Mac上netstat不太好用谣蠢,只能用lsof了):

[guodong@MacBooktest]lsof-iTCP:2605

COMMANDPIDUSERFDTYPEDEVICESIZE/OFFNODENAME

telnet74131guodong3uIPv40x199db390a76b3eb30t0TCP192.168.199.155:50307->yy.yy.yy.yy:nsc-posa(ESTABLISHED)

yy.yy.yy.yy表示的遠(yuǎn)程云主機(jī)的IP

nsc-posa其實(shí)就是端口2605,因?yàn)?605也是某個(gè)經(jīng)典協(xié)議(NSC POSA)的默認(rèn)端口查近,所以這種網(wǎng)絡(luò)工具直接顯示成了那個(gè)協(xié)議的名稱(chēng)眉踱。

客戶(hù)端pid為74135。當(dāng)然霜威,我其實(shí)知道我是用telnet連接的谈喳,只是為了查pid的話(huà),ps aux|grep telnet也可以侥祭。

注意:為了測(cè)試叁执。我這里的echo_server是寫(xiě)的有問(wèn)題的鱼喉。就是沒(méi)有處理客戶(hù)端異常斷開(kāi)的事件跷究。

下面我kill掉telnet(kill -9 74131)坷虑。再回到云主機(jī)查看一下:

[guodong@yuntest]netstat-anp|grep2605

tcp000.0.0.0:26050.0.0.0:*LISTEN3354/./echo_server

tcp1172.12.0.2:2605xx.xx.xx.xx:31559CLOSE_WAIT3354/./echo_server

由于echo_server內(nèi)沒(méi)對(duì)連接異常進(jìn)行偵測(cè)和處理鲸沮。所以可以看到原先ESTABLISHED的連接變成了CLOSE_WAIT秩贰。并且會(huì)持續(xù)下去赔蒲。我們?cè)倏匆幌滤蜷_(kāi)的fd:

0->?/dev/pts/6

1->?/dev/pts/6

2->?/dev/pts/6

3->?anon_inode:[eventpoll]

4->?socket:[674865719]

5->?socket:[674865835]

5這個(gè)fd還存在矮燎,并且會(huì)一直存在毡证。所以當(dāng)有大量CLOSE_WAIT的時(shí)候會(huì)占用服務(wù)器的fd琼牧。而一個(gè)機(jī)器能打開(kāi)的fd數(shù)量是有限的恢筝。超過(guò)了哀卫,因?yàn)闊o(wú)法分配fd,就無(wú)法建立新連接啦撬槽!

2.2 怎么避免客戶(hù)端異常斷開(kāi)時(shí)的服務(wù)端CLOSE_WAIT此改?

有一個(gè)方法。比如我用了epoll侄柔,那么我監(jiān)聽(tīng)客戶(hù)端連接套接字(5)的EPOLLRDHUP這個(gè)事件共啃。當(dāng)客戶(hù)端意外斷開(kāi)時(shí),這個(gè)事件就會(huì)被觸發(fā)暂题,觸發(fā)之后移剪。我們針對(duì)性的對(duì)這個(gè)fd(5)執(zhí)行close()操作就可以了。改下代碼薪者,重新模擬一下上述流程纵苛,blabla細(xì)節(jié)略過(guò)。現(xiàn)在我們新echo_server啟動(dòng)言津。MacBook的telnet連接成功攻人。然后我kill掉了telnet。觀察一下云主機(jī)上的狀況:

[guodong@yuntest]netstat-anp|grep2605

tcp000.0.0.0:26050.0.0.0:*LISTEN7678/./echo_server

tcp1172.12.0.2:2605xx.xx.xx.xx:31559LAST_ACK

出現(xiàn)了LAST_ACK纺念。我們看下fd贝椿。命令:ls /proc/7678/fd -l

0->?/dev/pts/6

1->?/dev/pts/6

2->?/dev/pts/6

3->?anon_inode:[eventpoll]

4->?socket:[674905737]

fd(5)其實(shí)已經(jīng)關(guān)閉了。過(guò)一會(huì)我們重新netstat看下:

[guodong@yuntest]netstat-anp|grep2605

tcp000.0.0.0:26050.0.0.0:*LISTEN7678/./echo_server

LAST_ACK也消失了陷谱。為什么出現(xiàn)LAST_ACK烙博。翻到開(kāi)頭,看我那張圖把萄贰渣窜!

CLOSE_WAIT不會(huì)自動(dòng)消失,而LAST_TACK會(huì)超時(shí)自動(dòng)消失宪躯,時(shí)間很短乔宿,即使在其存續(xù)期內(nèi),fd其實(shí)也是關(guān)閉狀態(tài)访雪。實(shí)際我這個(gè)簡(jiǎn)單的程序详瑞,測(cè)試的時(shí)候不會(huì)每次都捕捉到LAST_WAIT。有時(shí)候用netstat 命令查看的時(shí)候臣缀,就是最終那副圖了坝橡。

3. 什么時(shí)候出現(xiàn)TIME_WAIT?

看我開(kāi)篇那個(gè)圖就知道了。

現(xiàn)在我kill掉我的echo_server!

[guodong@yuntest]netstat-anp|grep2605

tcp00172.17.0.2:2605xx.xx.xx.xx:51327TIME_WAIT

云主機(jī)上原先ESTABLISHED的那條瞬間變成TIME_WAIT了精置。

這個(gè)TIME_WAIT也是超時(shí)自動(dòng)消失的计寇。時(shí)間是2MSL。MSL是多長(zhǎng)?

cat/proc/sys/net/ipv4/tcp_fin_timeout

一般是60番宁。2MSL也就2分鐘元莫。在2分鐘之內(nèi),對(duì)服務(wù)端有啥副作用嗎蝶押?有踱蠢,但問(wèn)題不大。那就是這期間重新啟動(dòng)Server會(huì)報(bào)端口占用播聪。這個(gè)等待朽基,一方面是擔(dān)心對(duì)方收不到自己的確認(rèn)布隔,等對(duì)方重發(fā)FIN离陶。另一方面2MSL是報(bào)文的最長(zhǎng)生命周期,可以避免Server重啟(或其他Server綁同樣端口)接收到了上一次的數(shù)據(jù)衅檀。

當(dāng)然這個(gè)2MLS的等待招刨,也可以通過(guò)給socket添加選項(xiàng)(SO_REUSEADDR)的方式來(lái)避免。Server可以立即重啟(這樣Server的監(jiān)控進(jìn)程就可以放心的重新拉起Server啦)哀军。

通常情況下TIME_WAIT對(duì)服務(wù)端影響有限沉眶,而大量CLOSE_WAIT風(fēng)險(xiǎn)較高,但正確編寫(xiě)代碼基本可以避免杉适。為什么只說(shuō)通常情況呢谎倔?因?yàn)樯a(chǎn)環(huán)境是復(fù)雜的,一個(gè)服務(wù)通常會(huì)和多個(gè)下游服務(wù)用各種各樣的協(xié)議進(jìn)行通信猿推。TIME_WAIT和CLOSE_WAIT在一些異常條件下片习,還是會(huì)觸發(fā)的。

并不是說(shuō)TIME_WAIT就真的無(wú)風(fēng)險(xiǎn)蹬叭,其實(shí)無(wú)論是TIME_WAIT還是CLOSE_WAIT藕咏,永遠(yuǎn)記住當(dāng)你的服務(wù)出現(xiàn)這兩種現(xiàn)象的時(shí)候,它們只是某個(gè)問(wèn)題導(dǎo)致的結(jié)果秽五,而不是問(wèn)題本身孽查。有些網(wǎng)絡(luò)教程教你怎么調(diào)大這個(gè)或那個(gè)的OS系統(tǒng)設(shè)置,個(gè)人感覺(jué)只是治標(biāo)不治本坦喘。找到本質(zhì)原因盲再,避免TIME_WAIT和CLOSE_WAIT的產(chǎn)生,才是問(wèn)題解決之道瓣铣!

把這些了解清楚時(shí)候答朋,是不是可以輕松應(yīng)對(duì)什么4次揮手之類(lèi)的面試題了?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末坯沪,一起剝皮案震驚了整個(gè)濱河市绿映,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖叉弦,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丐一,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡淹冰,警方通過(guò)查閱死者的電腦和手機(jī)库车,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)樱拴,“玉大人柠衍,你說(shuō)我怎么就攤上這事【牵” “怎么了珍坊?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)正罢。 經(jīng)常有香客問(wèn)我阵漏,道長(zhǎng),這世上最難降的妖魔是什么翻具? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任履怯,我火速辦了婚禮,結(jié)果婚禮上裆泳,老公的妹妹穿的比我還像新娘叹洲。我一直安慰自己,他們只是感情好工禾,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布运提。 她就那樣靜靜地躺著,像睡著了一般帜篇。 火紅的嫁衣襯著肌膚如雪糙捺。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,764評(píng)論 1 290
  • 那天笙隙,我揣著相機(jī)與錄音洪灯,去河邊找鬼。 笑死竟痰,一個(gè)胖子當(dāng)著我的面吹牛签钩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坏快,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼铅檩,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了莽鸿?” 一聲冷哼從身側(cè)響起昧旨,我...
    開(kāi)封第一講書(shū)人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤拾给,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后兔沃,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蒋得,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年乒疏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了额衙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡怕吴,死狀恐怖窍侧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情转绷,我是刑警寧澤伟件,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站暇咆,受9級(jí)特大地震影響锋爪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜爸业,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望亏镰。 院中可真熱鬧扯旷,春花似錦、人聲如沸索抓。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)逼肯。三九已至耸黑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間篮幢,已是汗流浹背大刊。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留三椿,地道東北人缺菌。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像搜锰,于是被迫代替她去往敵國(guó)和親伴郁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 概述:作為一名運(yùn)維工程師偶爾會(huì)遇到服務(wù)器出現(xiàn)大量TIME_WAIT或CLOSE_WAIT的連接狀態(tài)蛋叼。下面就來(lái)分析下...
    wangfs閱讀 13,003評(píng)論 3 12
  • 1焊傅、TIME_WAIT狀態(tài)存在的兩個(gè)理由: 1)讓4次握手關(guān)閉流程更加可靠;4次握手的最后一個(gè)ACK是是由主動(dòng)關(guān)閉...
    _科長(zhǎng)_閱讀 1,157評(píng)論 0 0
  • 為什么要有TIME_WAIT呢剂陡? 1.可靠地實(shí)現(xiàn)TCP全雙工連接的終止。A發(fā)送FIN到B狐胎,B收到FIN后發(fā)送ACK...
    Drama_Du閱讀 761評(píng)論 0 0
  • linux和windows下TIME_WAIT過(guò)多的解決辦法 如果使用了nginx代理鹏倘,那么系統(tǒng)TIME_WAIT...
    嘿嘿逗閱讀 908評(píng)論 0 0
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月,有人笑有人哭顽爹,有人歡樂(lè)有人憂(yōu)愁纤泵,有人驚喜有人失落,有的覺(jué)得收獲滿(mǎn)滿(mǎn)有...
    陌忘宇閱讀 8,528評(píng)論 28 53