1. 程式人生 > 其它 >TCP連線 關於三次握手與四次揮手

TCP連線 關於三次握手與四次揮手

1 TCP連線中的標誌位與序號

1.1 標誌位

  1. SYN: Synchronize Sequence Numbers 同步序列編號,SYN是TCP建立連線時的握手訊號,表示發起一次新連線
  2. ACK: 確認序號有效,用於應答
  3. FIN: 釋放一個連線
  4. RST: 重置連線

1.2 序號

  1. seq: 隨機產生的32位序列號,用來標識客戶端傳送的位元組流
  2. ack: 32位確認字元序號,當ACK=1時確認序號才有效,ack=seq+1

2 三次握手

三次握手是指成功建立一次TCP連線時客戶端和服務端一共傳送三個資料包的過程。
三次握手的目的是確認客戶端和服務端雙方的傳送、接收能力正常,保證TCP連線的可靠性。

三次握手的建立過程如下:

初始階段:
客戶端處於CLOSED狀態,服務端處於LISTEN狀態

  1. 第一次握手:
    客戶端向服務端傳送同步標誌SYN=1,序號seq=x
    客戶端進入SYN_SENT狀態
  2. 第二次握手:
    服務端向客戶端傳送SYN=1,序號seq=y,確認識別符號ACK=1,確認序號ack=x+1
    服務端進入SYN_RECV狀態
  3. 第三次握手:
    客戶端向服務端傳送序號seq=x+1,確認識別符號ACK=1,確認序號ack=y+1
    (注意,客戶端、服務端向對方傳送第一次請求的時候才傳送同步識別符號SYN,第三次握手不需要再發了)
    連線狀態:
    第三次握手之後,客戶端和服務端都進入已連線狀態established,TCP三次握手過程完成

2.1 連線佇列與重傳機制 丟包問題

第一次握手,當服務端收到客戶端的報文時,進入SYN_RCVD狀態,此時還沒有進入完全的連線狀態,會把本次連線請求放在半連線佇列裡,同時向客戶端傳送SYN-ACK包開始第二次握手,此時如果未收到客戶端的確認包,服務端則會進行首次重傳,超過一定時間之後會進行後續次數的重傳,這個時間一般按照指數級別增長。如果超過最大重傳次數,系統就會將該連線資訊從半連線佇列裡刪除。

如果已經順利完成三次握手進入連線狀態,則會將此次連線新增到全連線佇列裡,如果全連線佇列滿了,則可能造成丟包

2.2 為什麼要三次握手?兩次為什麼不行?

1. 需要三次握手來確保連線是可靠的

要進行可靠的通訊,就必須確認客戶端和服務端二者的傳送、接收能力都沒有問題
第一次握手,伺服器收到客戶端的報文,可以確認客戶端的傳送能力沒有問題
第二次握手,客戶端收到服務端的報文,可以確認服務端的接收和傳送能力沒有問題
但是二次握手之後,服務端並不知道客戶端的接收能力有沒有問題,在第三次握手,客戶端在收到服務端的報文之後,給服務端傳送了新的報文,此時服務端確認了客戶端的接收能力沒有問題,二者進入established連線狀態

至此,客戶端和服務端的收發能力都得到了確認,本次TCP連線的可靠性也得到了保證

2. 只進行二次握手可能會造成資源的浪費

如果客戶端發出的連線請求沒有收到服務端的確認,於是一段時間之後客戶端又向服務端傳送連線請求,成功建立連線,完成資料傳輸。可能存在一種情況,第一次連線並沒有丟失,而是因為某個網路節點的原因延遲到達服務端,此時服務端誤以為是客戶端又發起新的連線,於是向客戶端發出確認,完成二次握手,同時等待客戶端傳送資料,但客戶端並不理會,從而造成服務端的資源浪費。

3 四次揮手

初始狀態
客戶端和服務端都為established連線狀態

  1. 第一次揮手
    當客戶端的資料傳輸完成後,客戶端向服務端發出釋放連線報文,標誌位為FIN=1,序列號為seq=x
    客戶端進入FIN_WAIT狀態

  2. 第二次揮手
    服務端收到客戶端發的FIN報文後給客戶端回覆確認報文ACK=1,確認號ack=x+1,序列號seq=y,服務端進入關閉等待狀態CLOSE-WAIT,因為可能還有資料沒發完,所以並不會立即發出FIN標誌位
    服務端進入CLOSE_WAIT狀態

  3. 第三次揮手
    服務端將最後資料傳送完畢後再次向客戶端傳送確認報文ACK=1,FIN=1,seq=z,ack=x+1
    客戶端進入LAST_ACK狀態

  4. 四次揮手
    客戶端受到服務端發的FIN報文後,向服務端發出確認報文ACK=1,確認號ack=z+1,seq=w。客戶端在2MSL(Maximum Segment Lifetime,2個最大報文生存時長)之後釋放TCP連線,服務端受到客戶端傳送的確認報文之後就會立馬釋放TCP連線,所以服務端結束TCP連線的時間要比客戶端早一些
    服務端收到確認報文之後釋放連線進入CLOSED狀態
    客戶端在等待2MSL之後進入CLOSED狀態

3.1 為什麼揮手要4次,三次不行?

斷開TCP連線的前提是,客戶端和服務端都沒有要傳送的資料了。
第一次揮手,客戶端傳送FIN,表示自己沒有資料要傳送了
第二次揮手,服務端先回復一個確認報文表示已收到客戶端報文,但是自己還有一些資料沒有傳送完,發完了才能給FIN報文
第三次揮手,服務端確保自己資料傳送完畢,給出FIN報文
第四次揮手,客戶端收到服務端的FIN報文,發出確認報文,等待2MSL之後釋放TCP連線,而服務端受到客戶端的確認報文之後立即釋放TCP連線

簡而言之,三次不行是因為第二次揮手的時候伺服器可能還有一些資料要傳送,因此不能立即給出FIN報文,只能先給客戶端一個確認報文完成第二次揮手,等待自己的資料傳送完了,才在第三次揮手的時候給出FIN報文,因此多了一次揮手過程

3.2 為什麼第四次揮手客戶端需要等待2MSL之後才能釋放TCP連線?

考慮到第四次揮手丟包的問題,如果第三次揮手後服務端沒有收到返回的確認報文,就會重發第三次揮手報文,MSL是最大報文生存時間,2MSL是報文一去一回最長時間,客戶端需要等待這麼長時間來確認服務端已經收到第四次揮手報文