TCP/IP 基本原理解析

日常開發(fā),測(cè)試過(guò)程中,特別是在壓力測(cè)試過(guò)程中,用netstat -nat查看,發(fā)現(xiàn)客戶端出現(xiàn)大量SYN_SENT狀態(tài), 服務(wù)端出現(xiàn)大量SYN_RCVD狀態(tài)連接,下面我們一起看下

  • 為什么會(huì)有這些狀態(tài)?
  • 出現(xiàn)這些狀態(tài)原因是什么?

TCP協(xié)議模型

1.png

IP和端口

解決了文章最開始提到的定位的問(wèn)題。
IP在互聯(lián)網(wǎng)中能唯一標(biāo)識(shí)一臺(tái)計(jì)算機(jī),是每一臺(tái)計(jì)算機(jī)的唯一標(biāo)識(shí)(身份證);網(wǎng)絡(luò)編程是和遠(yuǎn)程計(jì)算機(jī)的通信,所以必須先能定位到遠(yuǎn)程計(jì)算機(jī);IP幫助解決此問(wèn)題;一臺(tái)計(jì)算機(jī)中可能有很多進(jìn)程,具體和哪一個(gè)進(jìn)程進(jìn)行通信,這就得靠端口來(lái)識(shí)別;

TCP和UDP協(xié)議

  • TCP是Tranfer Control Protocol的簡(jiǎn)稱,是一種面向連接的保證可靠傳輸?shù)膮f(xié)議。通過(guò)TCP協(xié)議傳輸,得到的是一個(gè)順序的無(wú)差錯(cuò)的數(shù)據(jù)流。發(fā)送方和接收方的成對(duì)的兩個(gè)socket之間必須建立連接,以便在TCP協(xié)議的基礎(chǔ)上進(jìn)行通信,當(dāng)一個(gè)socket(通常都是server socket)等待建立連接時(shí),另一個(gè)socket可以要求進(jìn)行連接,一旦這兩個(gè)socket連接起來(lái),它們就可以進(jìn)行雙向數(shù)據(jù)目的地的時(shí)間以及內(nèi)容的正確性都是不能被保證的傳輸,雙方都可以進(jìn)行發(fā)送或接收操作。
  • UDP是User Datagram Protocol的簡(jiǎn)稱,是一種無(wú)連接的協(xié)議,每個(gè)數(shù)據(jù)報(bào)都是一個(gè)獨(dú)立的信息,包括完整的源地址或目的地址,它在網(wǎng)絡(luò)上以任何可能的路徑傳往目的地,因此能否到達(dá)目的地,到達(dá)。
  • 比較:
    • UDP:
      • 每個(gè)數(shù)據(jù)報(bào)中都給出了完整的地址信息,因此無(wú)需要建立發(fā)送方和接收方的連接。
      • UDP傳輸數(shù)據(jù)時(shí)是有大小限制的,每個(gè)被傳輸?shù)臄?shù)據(jù)報(bào)必須限定在64KB之內(nèi)。
      • UDP是一個(gè)不可靠的協(xié)議,發(fā)送方所發(fā)送的數(shù)據(jù)報(bào)并不一定以相同的次序到達(dá)接收方
    • TCP:
      • 面向連接的協(xié)議,在socket之間進(jìn)行數(shù)據(jù)傳輸之前必然要建立連接,所以在TCP中需要連接時(shí)間。
      • TCP傳輸數(shù)據(jù)大小限制,一旦連接建立起來(lái),雙方的socket就可以按統(tǒng)一的格式傳輸大的數(shù)據(jù)。
      • TCP是一個(gè)可靠的協(xié)議,它確保接收方完全正確地獲取發(fā)送方所發(fā)送的全部數(shù)據(jù)。
        • 應(yīng)用數(shù)據(jù)分割成TCP認(rèn)為最適合發(fā)送的數(shù)據(jù)塊。這部分是通過(guò)“MSS”(最大數(shù)據(jù)包長(zhǎng)度)選項(xiàng)來(lái)控制的,通常這種機(jī)制也被稱為一種協(xié)商機(jī)制,MSS規(guī)定了TCP傳往另一端的最大數(shù)據(jù)塊的長(zhǎng)度。值得注意的是,MSS只能出現(xiàn)在SYN報(bào)文段中,若一方不接收來(lái)自另一方的MSS值,則MSS就定為536字節(jié)。一般來(lái)講,在不出現(xiàn)分段的情況下,MSS值還是越大越好,這樣可以提高網(wǎng)絡(luò)的利用率。
        • 重傳機(jī)制。設(shè)置定時(shí)器,等待確認(rèn)包。
        • 對(duì)首部和數(shù)據(jù)進(jìn)行校驗(yàn)。
        • TCP對(duì)收到的數(shù)據(jù)進(jìn)行排序,然后交給應(yīng)用層。
        • TCP的接收端丟棄重復(fù)的數(shù)據(jù)。
        • TCP還提供流量控制。(通過(guò)每一端聲明的窗口大小來(lái)提供的)

TCP狀態(tài)機(jī)

2.jpg

TCP狀態(tài)圖

  • 連接建立

    • 第一次握手:主機(jī)A發(fā)送位碼為syn=1,隨機(jī)產(chǎn)生seq number=1234567的數(shù)據(jù)包到服務(wù)器,主機(jī)B由SYN=1知道,A要求建立聯(lián)機(jī);
    • 第二次握手:主機(jī)B收到請(qǐng)求后要確認(rèn)聯(lián)機(jī)信息,向A發(fā)送ack number=(主機(jī)A的seq+1),syn=1,ack=1,隨機(jī)產(chǎn)生seq=7654321的包
    • 第三次握手:主機(jī)A收到后檢查ack number是否正確,即第一次發(fā)送的seq number+1,以及位碼ack是否為1,若正確,主機(jī)A會(huì)再發(fā)送ack number=(主機(jī)B的seq+1),ack=1,主機(jī)B收到后確認(rèn)seq值與ack=1則連接建立成功。
    • 完成三次握手,主機(jī)A與主機(jī)B開始傳送數(shù)據(jù)。
  • 連接關(guān)閉, 由于TCP連接是全雙工的,因此每個(gè)方向都必須單獨(dú)進(jìn)行關(guān)閉。這個(gè)原則是當(dāng)一方完成它的數(shù)據(jù)發(fā)送任務(wù)后就能發(fā)送一個(gè)FIN來(lái)終止這個(gè)方向的連接。收到一個(gè) FIN只意味著這一方向上沒(méi)有數(shù)據(jù)流動(dòng),一個(gè)TCP連接在收到一個(gè)FIN后仍能發(fā)送數(shù)據(jù)。首先進(jìn)行關(guān)閉的一方將執(zhí)行主動(dòng)關(guān)閉,而另一方執(zhí)行被動(dòng)關(guān)閉。

    • 客戶端A發(fā)送一個(gè)FIN,用來(lái)關(guān)閉客戶A到服務(wù)器B的數(shù)據(jù)傳送(報(bào)文段4)。
    • 服務(wù)器B收到這個(gè)FIN,它發(fā)回一個(gè)ACK,確認(rèn)序號(hào)為收到的序號(hào)加1(報(bào)文段5)。和SYN一樣,一個(gè)FIN將占用一個(gè)序號(hào)。
    • 服務(wù)器B關(guān)閉與客戶端A的連接,發(fā)送一個(gè)FIN給客戶端A(報(bào)文段6)。
    • 客戶端A發(fā)回ACK報(bào)文確認(rèn),并將確認(rèn)序號(hào)設(shè)置為收到序號(hào)加1(報(bào)文段7)。
      附上另一張圖:
3.png

TCP狀態(tài)

  • CLOSED: 表示初始狀態(tài)。

  • LISTEN: 表示服務(wù)器端的某個(gè)SOCKET處于監(jiān)聽(tīng)狀態(tài),可以接受連接了。

  • SYN_RCVD: 這個(gè)狀態(tài)表示接受到了SYN報(bào)文,在正常情況下,這個(gè)狀態(tài)是服務(wù)器端的SOCKET在建立TCP連接時(shí)的三次握手會(huì)話過(guò)程中的一個(gè)中間狀態(tài),很短暫,基本 上用netstat你是很難看到這種狀態(tài)的,除非你特意寫了一個(gè)客戶端測(cè)試程序,故意將三次TCP握手過(guò)程中最后一個(gè)ACK報(bào)文不予發(fā)送。因此這種狀態(tài) 時(shí),當(dāng)收到客戶端的ACK報(bào)文后,它會(huì)進(jìn)入到ESTABLISHED狀態(tài)。

  • SYN_SENT: 這個(gè)狀態(tài)與SYN_RCVD遙想呼應(yīng),當(dāng)客戶端SOCKET執(zhí)行CONNECT連接時(shí),它首先發(fā)送SYN報(bào)文,因此也隨即它會(huì)進(jìn)入到了SYN_SENT狀態(tài),并等待服務(wù)端的發(fā)送三次握手中的第2個(gè)報(bào)文。SYN_SENT狀態(tài)表示客戶端已發(fā)送SYN報(bào)文。

  • ESTABLISHED:表示連接已經(jīng)建立。

  • FIN_WAIT_1: 這個(gè)狀態(tài)要好好解釋一下,其實(shí)FIN_WAIT_1和FIN_WAIT_2狀態(tài)的真正含義都是表示等待對(duì)方的FIN報(bào)文。而這兩種狀態(tài)的區(qū)別 是:FIN_WAIT_1狀態(tài)實(shí)際上是當(dāng)SOCKET在ESTABLISHED狀態(tài)時(shí),它想主動(dòng)關(guān)閉連接,向?qū)Ψ桨l(fā)送了FIN報(bào)文,此時(shí)該SOCKET即 進(jìn)入到FIN_WAIT_1狀態(tài)。而當(dāng)對(duì)方回應(yīng)ACK報(bào)文后,則進(jìn)入到FIN_WAIT_2狀態(tài),當(dāng)然在實(shí)際的正常情況下,無(wú)論對(duì)方何種情況下,都應(yīng)該馬 上回應(yīng)ACK報(bào)文,所以FIN_WAIT_1狀態(tài)一般是比較難見(jiàn)到的,而FIN_WAIT_2狀態(tài)還有時(shí)常常可以用netstat看到。

  • FIN_WAIT_2:上面已經(jīng)詳細(xì)解釋了這種狀態(tài),實(shí)際上FIN_WAIT_2狀態(tài)下的SOCKET,表示半連接,也即有一方要求close連接,但另外還告訴對(duì)方,我暫時(shí)還有點(diǎn)數(shù)據(jù)需要傳送給你,稍后再關(guān)閉連接。

  • TIME_WAIT: 表示收到了對(duì)方的FIN報(bào)文,并發(fā)送出了ACK報(bào)文,就等2MSL后即可回到CLOSED可用狀態(tài)了。如果FIN_WAIT_1狀態(tài)下,收到了對(duì)方同時(shí)帶FIN標(biāo)志和ACK標(biāo)志的報(bào)文時(shí),可以直接進(jìn)入到TIME_WAIT狀態(tài),而無(wú)須經(jīng)過(guò)FIN_WAIT_2狀態(tài)。

  • CLOSE_WAIT: 這種狀態(tài)的含義其實(shí)是表示在等待關(guān)閉。怎么理解呢?當(dāng)對(duì)方close一個(gè)SOCKET后發(fā)送FIN報(bào)文給自己,你系統(tǒng)毫無(wú)疑問(wèn)地會(huì)回應(yīng)一個(gè)ACK報(bào)文給對(duì) 方,此時(shí)則進(jìn)入到CLOSE_WAIT狀態(tài)。接下來(lái)呢,實(shí)際上你真正需要考慮的事情是察看你是否還有數(shù)據(jù)發(fā)送給對(duì)方,如果沒(méi)有的話,那么你也就可以 close這個(gè)SOCKET,發(fā)送FIN報(bào)文給對(duì)方,也即關(guān)閉連接。所以你在CLOSE_WAIT狀態(tài)下,需要完成的事情是等待你去關(guān)閉連接。

  • LAST_ACK: 這個(gè)狀態(tài)還是比較容易好理解的,它是被動(dòng)關(guān)閉一方在發(fā)送FIN報(bào)文后,最后等待對(duì)方的ACK報(bào)文。當(dāng)收到ACK報(bào)文后,也即可以進(jìn)入到CLOSED可用狀態(tài)了。

  • CLOSING: 這種狀態(tài)比較特殊,實(shí)際情況中應(yīng)該是很少見(jiàn),屬于一種比較罕見(jiàn)的例外狀態(tài)。正常情況下,當(dāng)你發(fā)送FIN報(bào)文后,按理來(lái)說(shuō)是應(yīng)該先收到(或同時(shí)收到)對(duì)方的 ACK報(bào)文,再收到對(duì)方的FIN報(bào)文。但是CLOSING狀態(tài)表示你發(fā)送FIN報(bào)文后,并沒(méi)有收到對(duì)方的ACK報(bào)文,反而卻也收到了對(duì)方的FIN報(bào)文。什 么情況下會(huì)出現(xiàn)此種情況呢?其實(shí)細(xì)想一下,也不難得出結(jié)論:那就是如果雙方幾乎在同時(shí)close一個(gè)SOCKET的話,那么就出現(xiàn)了雙方同時(shí)發(fā)送FIN報(bào) 文的情況,也即會(huì)出現(xiàn)CLOSING狀態(tài),表示雙方都正在關(guān)閉SOCKET連接

通訊類型

  • 短連接
    • 連接 -> 數(shù)據(jù)傳輸 -> 關(guān)閉連接
  • 長(zhǎng)連接,要求長(zhǎng)連接在沒(méi)有數(shù)據(jù)通信時(shí),定時(shí)發(fā)送數(shù)據(jù)包,以維持連接狀態(tài),短連接在沒(méi)有數(shù)據(jù)傳輸時(shí)直接關(guān)閉就行了 長(zhǎng)連接需要心跳包維護(hù)連接狀態(tài)
    • 連接->數(shù)據(jù)傳輸->保持連接->數(shù)據(jù)傳輸->保持連接-> …… ->關(guān)閉連接

什么時(shí)候用長(zhǎng)連接,短連接?
長(zhǎng)連接主要用于在少數(shù)客戶端與服務(wù)端的頻繁通信,因?yàn)檫@時(shí)候如果用短連接頻繁通信常會(huì)發(fā)生Socket出錯(cuò),并且頻繁創(chuàng)建Socket連接也是對(duì)資源的浪費(fèi)。?
但是對(duì)于服務(wù)端來(lái)說(shuō),長(zhǎng)連接也會(huì)耗費(fèi)一定的資源,需要專門的線程來(lái)負(fù)責(zé)維護(hù)連接狀態(tài)。

  • 同步通訊--報(bào)文發(fā)送和接收是同步進(jìn)行,既報(bào)文發(fā)送后等待接收返回報(bào)文。

    • 發(fā)送數(shù)據(jù)之后等待接收返回?cái)?shù)據(jù)。同步方式一般需要考慮超時(shí)問(wèn)題,即報(bào)文發(fā)上去后不能無(wú)限等待,需要設(shè)定超時(shí)時(shí)間,超過(guò)該時(shí)間發(fā)送方不再等待讀返回報(bào)文,直接通知超時(shí)返回。
  • 異步通訊--報(bào)文發(fā)送和接收是分開的,相互獨(dú)立的,互不影響。這種方式又分兩種情況:

    • 異步雙工:接收和發(fā)送在同一個(gè)程序中,有兩個(gè)不同的子進(jìn)程分別負(fù)責(zé)發(fā)送和接收
    • 異步單工:接收和發(fā)送是用兩個(gè)不同的程序來(lái)完成。

日常應(yīng)用

我們通過(guò)了解TCP各個(gè)狀態(tài),可以排除和定位網(wǎng)絡(luò)或系統(tǒng)故障時(shí)大有幫助。

linux查看tcp的狀態(tài)命令:

  1. netstat -nat 查看TCP各個(gè)狀態(tài)的數(shù)量
  2. lsof -i:port 可以檢測(cè)到打開套接字的狀況
  3. tcpdump -iany tcp port 9000 對(duì)tcp端口為9000的進(jìn)行抓包

故障排查

通過(guò)端口監(jiān)聽(tīng)判斷服務(wù)啟動(dòng)是否正常
netstat –an| grep 8080

  1. 例如:提供www服務(wù)默認(rèn)開的是80端口,提供ftp服務(wù)默認(rèn)的端口為21,當(dāng)提供的服務(wù)沒(méi)有被連接時(shí)就處于LISTENING狀態(tài)。FTP服務(wù)啟動(dòng)后首先處于偵聽(tīng)(LISTENING)狀態(tài)。處于偵聽(tīng)LISTENING狀態(tài)時(shí),該端口是開放的,等待連接
  2. 客戶端出現(xiàn)大量SYN_SENT狀態(tài)
    • 當(dāng)請(qǐng)求連接時(shí)客戶端首先要發(fā)送同步信號(hào)給要訪問(wèn)的機(jī)器,此時(shí)狀態(tài)為SYN_SENT,如果連接成功了就變?yōu)镋STABLISHED,正常情況下SYN_SENT狀態(tài)非常短暫
    • 如果發(fā)現(xiàn)有很多SYN_SENT出現(xiàn),那一般有這么幾種情況,一是你要訪問(wèn)的服務(wù)器網(wǎng)絡(luò)不好,二是服務(wù)端無(wú)法建立連接返回ack
  3. 服務(wù)端出現(xiàn)大量SYN_RCVD狀態(tài)連接
    • 同理SYN_RCVD狀態(tài)也是非常短暫的,如果大量出現(xiàn)說(shuō)明有可能遭到了攻擊,或者是客戶端網(wǎng)絡(luò)限制
  4. 大量的CLOSE-WAIT狀態(tài)
    • 被動(dòng)關(guān)閉(passive close)端TCP接到FIN后,就發(fā)出ACK以回應(yīng)FIN請(qǐng)求(它的接收也作為文件結(jié)束符傳遞給上層應(yīng)用程序),并進(jìn)CLOSE_WAIT.如果連接不關(guān)閉CLOSE_WAIT持續(xù)時(shí)間會(huì)非常長(zhǎng),如果長(zhǎng)時(shí)間積累,可能會(huì)導(dǎo)致系統(tǒng)資源耗盡
  5. 發(fā)現(xiàn)系統(tǒng)存在大量TIME_WAIT狀態(tài)的連接,可以修改內(nèi)核參數(shù)解決,修改TIME_WAIT持續(xù)時(shí)間
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 1、TCP狀態(tài)linux查看tcp的狀態(tài)命令:1)、netstat -nat 查看TCP各個(gè)狀態(tài)的數(shù)量2)、lso...
    北辰青閱讀 9,509評(píng)論 0 11
  • 個(gè)人認(rèn)為,Goodboy1881先生的TCP /IP 協(xié)議詳解學(xué)習(xí)博客系列博客是一部非常精彩的學(xué)習(xí)筆記,這雖然只是...
    貳零壹柒_fc10閱讀 5,091評(píng)論 0 8
  • 18.1 引言 TCP是一個(gè)面向連接的協(xié)議。無(wú)論哪一方向另一方發(fā)送數(shù)據(jù)之前,都必須先在雙方之間建立一條連接。本章將...
    張芳濤閱讀 3,425評(píng)論 0 13
  • 1.這篇文章不是本人原創(chuàng)的,只是個(gè)人為了對(duì)這部分知識(shí)做一個(gè)整理和系統(tǒng)的輸出而編輯成的,在此鄭重地向本文所引用文章的...
    SOMCENT閱讀 13,132評(píng)論 6 174
  • 最近在惡補(bǔ)計(jì)算機(jī)網(wǎng)絡(luò)方面的知識(shí),之前對(duì)于TCP的三次握手和四次分手也是模模糊糊,對(duì)于其中的細(xì)節(jié)更是渾然不知,最近看...
    微醺歲月閱讀 9,559評(píng)論 4 128