tft每日頭條

 > 生活

 > tcp協議如何開啟

tcp協議如何開啟

生活 更新时间:2024-09-16 12:17:19
linux服務器開發相關視頻解析:

10道經典面試題的剖析, 技術方向如何決定職業方向|c/c |linux

徒手實現網絡協議棧,請準備好環境,一起來寫代碼

linux多線程之epoll原理剖析與reactor原理及應用

CLOSE_WAIT和TIME_WAIT是如何産生的?大量的CLOSE_WAIT和TIME_WAIT又有何隐患?本文将通過實踐角度來帶你揭開CLOSE_WAIT和TIME_WAIT的神秘面紗!遇事不決先祭此圖:

tcp協議如何開啟(通過實踐帶你揭開TCP中CLOSE)1

稍微補充一點:TIME_WAIT到CLOSED,這一步是超時自動遷移。

兩條豎線分别是表示:

  • 主動關閉(active close)的一方
  • 被動關閉(passive close)的一方

網絡上類似的圖有很多,但是有的細節不夠,有的存在誤導。有的會把兩條線分别标記成Client和Server。給讀者造成困惑。對于斷開連接這件事,客戶端和服務端都能作為主動方發起,也就是「主動關閉」可以是客戶端,可以是服務端。而對端相應的就是「被動關閉」。不管誰發起,狀态遷移如上圖。

1. 耗盡的是誰的端口?

首先解答初學者對socket的認識存在一個常見的誤區。作為服務端,不管哪個WAIT都不會耗盡客戶端的端口!

舉個例子,我在某雲的雲主機上有個Server程序:echo_server。我啟動它,監聽2605端口。然後我在自己的MacBook上用telnet去連接它。連上之後,在雲主機上用 netstat -anp看一下:

[guodong@yuntest]netstat-anp|grep2605 tcp000.0.0.0:26050.0.0.0:*LISTEN3354/./echo_server tcp0172.12.0.2:2605xx.xx.xx.xx:31559ESTABLISHED3354/./echo_server

xx.xx.xx.xx是我Macbook的本機IP

其中有兩條記錄,LISTEN的表示是我的echo_server監聽一個端口。ESTABLISHED表示已經有一個客戶端連接了。第三列的IP端口是我echo_server的(這個顯示IP是局域網的;第四列顯示的是客戶端的IP和端口,也就是我MacBook。

要說明的是這個端口:31559是客戶端的。這個是建立連接時的MacBook分配的随機端口。

我們看一下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是三巨頭(标準輸入,輸出,錯誤)自不必言。3是因為我使用了epoll,所以有一個epfd。

4其實就是我服務端監聽端口打開的被動套接字;

5就是客戶端建立連接到時候,分配給客戶端的連接套接字。server程序隻要給5這個fd寫數據,就相當于返回數據給客戶端。

服務端怎麼會耗盡客戶端的端口号的。這裡消耗的其實是服務端的fd(也不是端口)!

【文章福利】需要C/C Linux服務器架構師學習資料加群812855908(資料包括C/C ,Linux,golang技術,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK,ffmpeg等)

tcp協議如何開啟(通過實踐帶你揭開TCP中CLOSE)2

2. 什麼時候出現CLOSE_WAIT?

2.1 舉個例子

回到我的MacBook終端,查看一下2605有關的連接(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表示的遠程雲主機的IP

nsc-posa其實就是端口2605,因為2605也是某個經典協議(NSC POSA)的默認端口,所以這種網絡工具直接顯示成了那個協議的名稱。

客戶端pid為74135。當然,我其實知道我是用telnet連接的,隻是為了查pid的話,ps aux|grep telnet也可以。

注意:為了測試。我這裡的echo_server是寫的有問題的。就是沒有處理客戶端異常斷開的事件。

下面我kill掉telnet(kill -9 74131)。再回到雲主機查看一下:

[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内沒對連接異常進行偵測和處理。所以可以看到原先ESTABLISHED的連接變成了CLOSE_WAIT。并且會持續下去。我們再看一下它打開的fd:

0->/dev/pts/6 1->/dev/pts/6 2->/dev/pts/6 3->anon_inode:[eventpoll] 4->socket:[674865719] 5->socket:[674865835]

5這個fd還存在,并且會一直存在。所以當有大量CLOSE_WAIT的時候會占用服務器的fd。而一個機器能打開的fd數量是有限的。超過了,因為無法分配fd,就無法建立新連接啦!

2.2 怎麼避免客戶端異常斷開時的服務端CLOSE_WAIT?

有一個方法。比如我用了epoll,那麼我監聽客戶端連接套接字(5)的EPOLLRDHUP這個事件。當客戶端意外斷開時,這個事件就會被觸發,觸發之後。我們針對性的對這個fd(5)執行close()操作就可以了。改下代碼,重新模拟一下上述流程,blabla細節略過。現在我們新echo_server啟動。MacBook的telnet連接成功。然後我kill掉了telnet。觀察一下雲主機上的狀況:

[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-

出現了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)其實已經關閉了。過一會我們重新netstat看下:

[guodong@yuntest]netstat-anp|grep2605 tcp000.0.0.0:26050.0.0.0:*LISTEN7678/./echo_server

LAST_ACK也消失了。為什麼出現LAST_ACK。翻到開頭,看我那張圖啊!

CLOSE_WAIT不會自動消失,而LAST_TACK會超時自動消失,時間很短,即使在其存續期内,fd其實也是關閉狀态。實際我這個簡單的程序,測試的時候不會每次都捕捉到LAST_WAIT。有時候用netstat 命令查看的時候,就是最終那副圖了。

3. 什麼時候出現TIME_WAIT?

看我開篇那個圖就知道了。

現在我kill掉我的echo_server!

[guodong@yuntest]netstat-anp|grep2605 tcp00172.17.0.2:2605xx.xx.xx.xx:51327TIME_WAIT-

雲主機上原先ESTABLISHED的那條瞬間變成TIME_WAIT了。

這個TIME_WAIT也是超時自動消失的。時間是2MSL。MSL是多長?

cat/proc/sys/net/ipv4/tcp_fin_timeout

一般是60。2MSL也就2分鐘。在2分鐘之内,對服務端有啥副作用嗎?有,但問題不大。那就是這期間重新啟動Server會報端口占用。這個等待,一方面是擔心對方收不到自己的确認,等對方重發FIN。另一方面2MSL是報文的最長生命周期,可以避免Server重啟(或其他Server綁同樣端口)接收到了上一次的數據。

當然這個2MLS的等待,也可以通過給socket添加選項(SO_REUSEADDR)的方式來避免。Server可以立即重啟(這樣Server的監控進程就可以放心的重新拉起Server啦)。

通常情況下TIME_WAIT對服務端影響有限,而大量CLOSE_WAIT風險較高,但正确編寫代碼基本可以避免。為什麼隻說通常情況呢?因為生産環境是複雜的,一個服務通常會和多個下遊服務用各種各樣的協議進行通信。TIME_WAIT和CLOSE_WAIT在一些異常條件下,還是會觸發的。

并不是說TIME_WAIT就真的無風險,其實無論是TIME_WAIT還是CLOSE_WAIT,永遠記住當你的服務出現這兩種現象的時候,它們隻是某個問題導緻的結果,而不是問題本身。有些網絡教程教你怎麼調大這個或那個的OS系統設置,個人感覺隻是治标不治本。找到本質原因,避免TIME_WAIT和CLOSE_WAIT的産生,才是問題解決之道!

把這些了解清楚時候,是不是可以輕松應對什麼4次揮手之類的面試題了?

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved