天天看點

TCP連接配接與釋放——三次握手和四次揮手(詳解+動圖)

背景描述

我們知道網絡層,可以實作兩個主機之間的通信。但是這并不具體,因為,真正進行通信的實體是在主機中的程序,是一個主機中的一個程序與另外一個主機中的一個程序在交換資料。IP協定雖然能把資料封包送到目的主機,但是并沒有傳遞給主機的具體應用程序。而端到端的通信才應該是應用程序之間的通信。

UDP,在傳送資料前不需要先建立連接配接,遠地的主機在收到UDP封包後也不需要給出任何确認。雖然UDP不提供可靠傳遞,但是正是因為這樣,省去和很多的開銷,使得它的速度比較快,比如一些對實時性要求較高的服務,就常常使用的是UDP。對應的應用層的協定主要有 DNS,TFTP,DHCP,SNMP,NFS 等。

TCP,提供面向連接配接的服務,在傳送資料之前必須先建立連接配接,資料傳送完成後要釋放連接配接。是以TCP是一種可靠的的運輸服務,但是正因為這樣,不可避免的增加了許多的開銷,比如确認,流量控制等。對應的應用層的協定主要有 SMTP,TELNET,HTTP,FTP 等。

常用的熟知端口号

應用程式 FTP TFTP TELNET SMTP DNS HTTP SSH MYSQL
熟知端口 21,20 69 23 25 53 80 22 3306
傳輸層協定 TCP UDP TCP TCP UDP TCP

TCP的概述

TCP把連接配接作為最基本的對象,每一條TCP連接配接都有兩個端點,這種斷點我們叫作套接字(socket),它的定義為端口号拼接到IP位址即構成了套接字,例如,若IP位址為192.3.4.16 而端口号為80,那麼得到的套接字為192.3.4.16:80。

TCP封包首部

  1. 源端口和目的端口,各占2個位元組,分别寫入源端口和目的端口;
  2. 序号,占4個位元組,TCP連接配接中傳送的位元組流中的每個位元組都按順序編号。例如,一段封包的序号字段值是 301 ,而攜帶的資料共有100字段,顯然下一個封包段(如果還有的話)的資料序号應該從401開始;
  3. 确認号,占4個位元組,是期望收到對方下一個封包的第一個資料位元組的序号。例如,B收到了A發送過來的封包,其序列号字段是501,而資料長度是200位元組,這表明B正确的收到了A發送的到序号700為止的資料。是以,B期望收到A的下一個資料序号是701,于是B在發送給A的确認封包段中把确認号置為701;
  4. 資料偏移,占4位,它指出TCP封包的資料距離TCP封包段的起始處有多遠;
  5. 保留,占6位,保留今後使用,但目前應都位0;
  6. 緊急URG,當URG=1,表明緊急指針字段有效。告訴系統此封包段中有緊急資料;
  7. 确認ACK,僅當ACK=1時,确認号字段才有效。TCP規定,在連接配接建立後所有封包的傳輸都必須把ACK置1;
  8. 推送PSH,當兩個應用程序進行互動式通信時,有時在一端的應用程序希望在鍵入一個指令後立即就能收到對方的響應,這時候就将PSH=1;
  9. 複位RST,當RST=1,表明TCP連接配接中出現嚴重差錯,必須釋放連接配接,然後再重建立立連接配接;
  10. 同步SYN,在連接配接建立時用來同步序号。當SYN=1,ACK=0,表明是連接配接請求封包,若同意連接配接,則響應封包中應該使SYN=1,ACK=1;
  11. 終止FIN,用來釋放連接配接。當FIN=1,表明此封包的發送方的資料已經發送完畢,并且要求釋放;
  12. 視窗,占2位元組,指的是通知接收方,發送本封包你需要有多大的空間來接受;
  13. 檢驗和,占2位元組,校驗首部和資料這兩部分;
  14. 緊急指針,占2位元組,指出本封包段中的緊急資料的位元組數;
  15. 選項,長度可變,定義一些其他的可選的參數。

TCP連接配接的建立(三次握手)

TCP連接配接與釋放——三次握手和四次揮手(詳解+動圖)
最開始的時候用戶端和伺服器都是處于CLOSED狀态。主動打開連接配接的為用戶端,被動打開連接配接的是伺服器。
  1. TCP伺服器程序先建立傳輸控制塊TCB,時刻準備接受客戶程序的連接配接請求,此時伺服器就進入了LISTEN(監聽)狀态;
  2. TCP客戶程序也是先建立傳輸控制塊TCB,然後向伺服器發出連接配接請求封包,這是封包首部中的同部位SYN=1,同時選擇一個初始序列号 seq=x ,此時,TCP用戶端程序進入了 SYN-SENT(同步已發送狀态)狀态。TCP規定,SYN封包段(SYN=1的封包段)不能攜帶資料,但需要消耗掉一個序号。
  3. TCP伺服器收到請求封包後,如果同意連接配接,則發出确認封包。确認封包中應該 ACK=1,SYN=1,确認号是ack=x+1,同時也要為自己初始化一個序列号 seq=y,此時,TCP伺服器程序進入了SYN-RCVD(同步收到)狀态。這個封包也不能攜帶資料,但是同樣要消耗一個序号。
  4. TCP客戶程序收到确認後,還要向伺服器給出确認。确認封包的ACK=1,ack=y+1,自己的序列号seq=x+1,此時,TCP連接配接建立,用戶端進入ESTABLISHED(已建立連接配接)狀态。TCP規定,ACK封包段可以攜帶資料,但是如果不攜帶資料則不消耗序号。
  5. 當伺服器收到用戶端的确認後也進入ESTABLISHED狀态,此後雙方就可以開始通信了。 
    TCP連接配接與釋放——三次握手和四次揮手(詳解+動圖)

三次握手過程中參與的函數:

TCP連接配接與釋放——三次握手和四次揮手(詳解+動圖)

為什麼TCP用戶端最後還要發送一次确認呢?

一句話,主要防止已經失效的連接配接請求封包突然又傳送到了伺服器,進而産生錯誤。

如果使用的是兩次握手建立連接配接,假設有這樣一種場景,用戶端發送了第一個請求連接配接并且沒有丢失,隻是因為在網絡結點中滞留的時間太長了,由于TCP的用戶端遲遲沒有收到确認封包,以為伺服器沒有收到,此時重新向伺服器發送這條封包,此後用戶端和伺服器經過兩次握手完成連接配接,傳輸資料,然後關閉連接配接。此時此前滞留的那一次請求連接配接,網絡通暢了到達了伺服器,這個封包本該是失效的,但是,兩次握手的機制将會讓用戶端和伺服器再次建立連接配接,這将導緻不必要的錯誤和資源的浪費。

如果采用的是三次握手,就算是那一次失效的封包傳送過來了,服務端接受到了那條失效封包并且回複了确認封包,但是用戶端不會再次發出确認。由于伺服器收不到确認,就知道用戶端并沒有請求連接配接。

TCP連接配接的釋放(四次揮手)

TCP連接配接與釋放——三次握手和四次揮手(詳解+動圖)
資料傳輸完畢後,雙方都可釋放連接配接。最開始的時候,用戶端和伺服器都是處于ESTABLISHED狀态,然後用戶端主動關閉,伺服器被動關閉。
  1. 用戶端程序發出連接配接釋放封包,并且停止發送資料。釋放資料封包首部,FIN=1,其序列号為seq=u(等于前面已經傳送過來的資料的最後一個位元組的序号加1),此時,用戶端進入FIN-WAIT-1(終止等待1)狀态。 TCP規定,FIN封包段即使不攜帶資料,也要消耗一個序号。
  2. 伺服器收到連接配接釋放封包,發出确認封包,ACK=1,ack=u+1,并且帶上自己的序列号seq=v,此時,服務端就進入了CLOSE-WAIT(關閉等待)狀态。TCP伺服器通知高層的應用程序,用戶端向伺服器的方向就釋放了,這時候處于半關閉狀态,即用戶端已經沒有資料要發送了,但是伺服器若發送資料,用戶端依然要接受。這個狀态還要持續一段時間,也就是整個CLOSE-WAIT狀态持續的時間。
  3. 用戶端收到伺服器的确認請求後,此時,用戶端就進入FIN-WAIT-2(終止等待2)狀态,等待伺服器發送連接配接釋放封包(在這之前還需要接受伺服器發送的最後的資料)。
  4. 伺服器将最後的資料發送完畢後,就向用戶端發送連接配接釋放封包,FIN=1,ack=u+1,由于在半關閉狀态,伺服器很可能又發送了一些資料,假定此時的序列号為seq=w,此時,伺服器就進入了LAST-ACK(最後确認)狀态,等待用戶端的确認。
  5. 用戶端收到伺服器的連接配接釋放封包後,必須發出确認,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此時,用戶端就進入了TIME-WAIT(時間等待)狀态。注意此時TCP連接配接還沒有釋放,必須經過2∗∗MSL(最長封包段壽命)的時間後,當用戶端撤銷相應的TCB後,才進入CLOSED狀态。
  6. 伺服器隻要收到了用戶端發出的确認,立即進入CLOSED狀态。同樣,撤銷TCB後,就結束了這次的TCP連接配接。可以看到,伺服器結束TCP連接配接的時間要比用戶端早一些。
TCP連接配接與釋放——三次握手和四次揮手(詳解+動圖)
TCP連接配接與釋放——三次握手和四次揮手(詳解+動圖)

為什麼用戶端最後還要等待2MSL?

MSL(Maximum Segment Lifetime),TCP允許不同的實作可以設定不同的MSL值。

第一,保證用戶端發送的最後一個ACK封包能夠到達伺服器,因為這個ACK封包可能丢失,站在伺服器的角度看來,我已經發送了FIN+ACK封包請求斷開了,用戶端還沒有給我回應,應該是我發送的請求斷開封包它沒有收到,于是伺服器又會重新發送一次,而用戶端就能在這個2MSL時間段内收到這個重傳的封包,接着給出回應封包,并且會重新開機2MSL計時器。

第二,防止類似與“三次握手”中提到了的“已經失效的連接配接請求封包段”出現在本連接配接中。用戶端發送完最後一個确認封包後,在這個2MSL時間中,就可以使本連接配接持續的時間内所産生的所有封包段都從網絡中消失。這樣新的連接配接中不會出現舊連接配接的請求封包。

為什麼建立連接配接是三次握手,關閉連接配接确是四次揮手呢?

建立連接配接的時候, 伺服器在LISTEN狀态下,收到建立連接配接請求的SYN封包後,把ACK和SYN放在一個封包裡發送給用戶端。 

而關閉連接配接時,伺服器收到對方的FIN封包時,僅僅表示對方不再發送資料了但是還能接收資料,而自己也未必全部資料都發送給對方了,是以己方可以立即關閉,也可以發送一些資料給對方後,再發送FIN封包給對方來表示同意現在關閉連接配接,是以,己方ACK和FIN一般都會分開發送,進而導緻多了一次。

如果已經建立了連接配接,但是用戶端突然出現故障了怎麼辦?

TCP還設有一個保活計時器,顯然,用戶端如果出現故障,伺服器不能一直等下去,白白浪費資源。伺服器每收到一次用戶端的請求後都會重新複位這個計時器,時間通常是設定為2小時,若兩小時還沒有收到用戶端的任何資料,伺服器就會發送一個探測封包段,以後每隔75分鐘發送一次。若一連發送10個探測封包仍然沒反應,伺服器就認為用戶端出了故障,接着就關閉連接配接。

參考文章:https://blog.csdn.net/qzcsu/article/details/72861891

繼續閱讀