1. 程式人生 > >TCP三次握手與四次揮手複習

TCP三次握手與四次揮手複習

TCP,提供面向連線的服務,在傳送資料之前必須先建立連線,資料傳送完成後要釋放連線。因此TCP是一種可靠的的運輸服務,但是正因為這樣,不可避免的增加了許多的開銷,比如確認,流量控制等

TCP連線的建立(三次握手)

 

三次握手(我要和你建立連結,你真的要和我建立連結麼,我真的要和你建立連結,成功):

前提:

TCP伺服器程序先建立傳輸控制塊TCB,時刻準備接受客戶程序的連線請求,此時伺服器就進入了LISTEN(監聽)狀態;(最開始的時候客戶端和伺服器都是處於CLOSED狀態。主動開啟連線的為客戶端,被動開啟連線的是伺服器。也就是Sotcket初始化

  • 第一次握手:Client將標誌位SYN置為1,隨機產生一個值seq=J,並將該資料包傳送給Server,Client進入SYN_SENT狀態,等待Server確認。

  • 第二次握手:Server收到資料包後由標誌位SYN=1知道Client請求建立連線,Server將標誌位SYN和ACK都置為1,ack=J+1,隨機產生一個值seq=K,並將該資料包傳送給Client以確認連線請求,Server進入SYN_RCVD狀態。

  • 第三次握手:Client收到確認後,檢查ack是否為J+1,ACK是否為1,如果正確則將標誌位ACK置為1,ack=K+1,並將該資料包傳送給Server,Server檢查ack是否為K+1,ACK是否為1,如果正確則連線建立成功,Client和Server進入ESTABLISHED狀態,完成三次握手,隨後Client與Server之間可以開始傳輸資料了。

為什麼TCP客戶端最後還要傳送一次確認呢?

一句話,主要防止已經失效的連線請求報文突然又傳送到了伺服器,從而產生錯誤。

如果使用的是兩次握手建立連線,假設有這樣一種場景,客戶端傳送了第一個請求連線並且沒有丟失,只是因為在網路結點中滯留的時間太長了,由於TCP的客戶端遲遲沒有收到確認報文,以為伺服器沒有收到,此時重新向伺服器傳送這條報文,此後客戶端和伺服器經過兩次握手完成連線,傳輸資料,然後關閉連線。此時此前滯留的那一次請求連線,網路通暢了到達了伺服器,這個報文字該是失效的,但是,兩次握手的機制將會讓客戶端和伺服器再次建立連線,這將導致不必要的錯誤和資源的浪費。

如果採用的是三次握手,就算是那一次失效的報文傳送過來了,服務端接受到了那條失效報文並且回覆了確認報文,但是客戶端不會再次發出確認。由於伺服器收不到確認,就知道客戶端並沒有請求連線。

 

TCP連線的釋放(四次揮手)

資料傳輸完畢後,雙方都可釋放連線。最開始的時候,客戶端和伺服器都是處於ESTABLISHED狀態,然後客戶端主動關閉,伺服器被動關閉。

 

(2). 四次揮手(我要和你斷開連結;好的,斷吧。我也要和你斷開連結;好的,斷吧):

  • 第一次揮手:Client傳送一個FIN,用來關閉Client到Server的資料傳送,Client進入FIN_WAIT_1狀態。

  • 第二次揮手:Server收到FIN後,傳送一個ACK給Client,確認序號為收到序號+1(與SYN相同,一個FIN佔用一個序號),Server進入CLOSE_WAIT狀態。此時TCP連結處於半關閉狀態,即客戶端已經沒有要傳送的資料了,但服務端若傳送資料,則客戶端仍要接收。

  • 第三次揮手:Server傳送一個FIN,用來關閉Server到Client的資料傳送,Server進入LAST_ACK狀態。

  • 第四次揮手:Client收到FIN後,Client進入TIME_WAIT狀態,接著傳送一個ACK給Server,確認序號為收到序號+1,Server進入CLOSED狀態,完成四次揮手。

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

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

第一,保證客戶端傳送的最後一個ACK報文能夠到達伺服器,因為這個ACK報文可能丟失,站在伺服器的角度看來,我已經發送了FIN+ACK報文請求斷開了,客戶端還沒有給我回應,應該是我傳送的請求斷開報文它沒有收到,於是伺服器又會重新發送一次,而客戶端就能在這個2MSL時間段內收到這個重傳的報文,接著給出迴應報文,並且會重啟2MSL計時器。

第二,防止類似與“三次握手”中提到了的“已經失效的連線請求報文段”出現在本連線中。客戶端傳送完最後一個確認報文後,在這個2MSL時間中,就可以使本連線持續的時間內所產生的所有報文段都從網路中消失。這樣新的連線中不會出現舊連線的請求報文。

為什麼建立連線是三次握手,關閉連線確是四次揮手呢?

建立連線的時候, 伺服器在LISTEN狀態下,收到建立連線請求的SYN報文後,把ACK和SYN放在一個報文裡傳送給客戶端。 
而關閉連線時,伺服器收到對方的FIN報文時,僅僅表示對方不再發送資料了但是還能接收資料,而自己也未必全部資料都發送給對方了,所以己方可以立即關閉,也可以傳送一些資料給對方後,再發送FIN報文給對方來表示同意現在關閉連線,因此,己方ACK和FIN一般都會分開發送,從而導致多了一次。
(防止關閉之前的資料丟失)