TCP 的 三次握手 四次握手

解釋 

  • 同步 SYN :synchronous。創建鏈接,將 SYN = 1。
  • 序號 seq: sequence。第一個字節的編號隨機產生。
  • 確認位 ACK : acknowledgement 。
  • ack : 表示確認字段的值。(對哪一個進行確認)。
  • 結束 FIN : finish。FIN = 1 表示但願斷開鏈接。

狀態 

  • SYN-SENT : 同步已發送。
  • SYN-RCVD:同步收到。
  • ESTABLISHED: 已創建鏈接。
  • FIN-WAIT-1:終止等待1。
  • FIN-WAIT-2:終止等待2。
  • CLOSE-WAIT: 關閉等待。 
  • LAST-ACK : 最後確認。
  • TIME-WAIT: 時間等待。 
  • CLOSED :關閉狀態。

三報文握手

TCP創建鏈接的過程叫作握手,握手須要在客戶和服務器之間交換三個 TCP 報文段。html



最初,客戶端和服務器的 TCP 進程都處於 CLOSED (關閉) 狀態。B 的 TCP 服務器進程先建立 傳輸控制塊 TCB ,準備接受客戶進程的鏈接請求。而後服務器進程處於 LISTEN (收聽) 狀態,等待客戶的鏈接請求。A 的 TCP 客戶進程也是首先建立 傳輸控制塊 TCB
服務器

第一次握手 : 客戶端打算創建鏈接時,向服務器發出鏈接請求報文段,此時首部中的同步位 SYN = 1 ,同時選擇一個初始須要 seq = x 。 TCP 規定,SYN = 1 的報文段 不能攜帶數據,但要消耗掉一個序號。這時,TCP 客戶進程進入 SYN-SENT (同步已發送)狀態。
網絡

第二次握手:服務器收到鏈接請求報文段後,若是贊成創建鏈接,則向客戶端發送確認。在確認報文段中應把 SYN 位 和 ACK 位 都置 1 ,確認號是 ack = x + 1,同時也爲本身選擇一個初始序號 seq = y。(這個報文段也不能攜帶數據,但一樣要消耗掉一個序號。)這時 TCP 服務器進程進入 SYN-RCVD (同步收到) 狀態。
計算機網絡

第三次握手:客戶端收到服務器的確認後,還要向服務器給出確認。確認報文段的 ACK 置爲 1 ,確認號 ack = y + 1,而本身的序號 seq = x + 1 。這時, TCP 鏈接已經創建,客戶端進入 ESTABLISHED (已創建鏈接) 狀態。當 服務器 收到 客戶端 的確認後,也進入 ESTABLISHED (已創建鏈接) 狀態。3d

經過這樣的三次握手,客戶端與服務器端創建可靠的雙工的鏈接,開始傳送數據。三次握手的主要目的是保證鏈接是雙工的,可靠更可能是經過重傳機制來保證的。
cdn

爲何 客戶端 最後還要發送一次確認?

主要是爲了防止已失效的鏈接請求報文段忽然又傳到了 服務器,於是產生錯誤。 htm

現假定出現一種異常狀況,即 客戶端 發出的第一個鏈接請求報文段並無丟失,而是在某些網絡結點長時間滯留了,以至延誤到鏈接釋放之後的某個時間纔到達 服務器。原本這是一個早已失效的報文段。但 服務器 收到此失效的鏈接請求報文段後,就誤認爲是 客戶端 又發出一次新的鏈接請求。因而就向 客戶端 發出確認報文段,贊成創建鏈接。假定不採用報文握手,那麼只要 服務器發出確認,新的鏈接就創建了。因爲如今 客戶端 並無發出創建鏈接的請求,所以不會理睬 服務器 的確認,也不會向 服務器 發送數據。可是 服務器 卻覺得新的運輸鏈接已經創建了,並一直等待 客戶端 發來數據。服務器 的許多資源就這樣白白浪費了。 採用三次報文握手的辦法,能夠防止上述現象的發生。假如在剛纔的異常狀況下,客戶端 不會像 服務器 的確認發出確認。服務器 因爲收不到確認,就知道 客戶端 並無要求創建鏈接。
blog

四報文握手

數據傳輸結束後,通訊的雙方均可以釋放資源。此時 客戶端 和 服務器 都處於 ESTABLISHED 狀態。進程



第一次握手 : 客戶端 的應用進程先向其 TCP 發出鏈接釋放報文段,並中止在發送數據,主動關閉 TCP 鏈接。客戶端把鏈接釋放報文段首部的終止控制位 FIN 置 1,其序號 seq = u ,它等於前面已傳過的數據的最後一個字節的序號加 1 。這時 客戶端 進入 FIN-WAIT-1 (終止等待1) 狀態,等待 服務器 的確認。( FIN 報文段即便不攜帶數據,它也消耗掉一個序號。)
資源

第二次握手:服務器收到鏈接釋放報文段後即發出確認,確認號 ack = u + 1 ,而這個報文段 本身的序號是 v ,等於 服務器 前面已經傳過的數據的最後一個字節的序號加 1 。而後 服務器 就進入 CLOSEWAIT(關閉等待)狀態。TCP 服務器進程這時應通知高層應用進程(不肯定本身是否還有數據要發送給 客戶端(因此是四次不是三次)),於是從 客戶端 到 服務器 這個方向的鏈接就釋放了,這時的 TCP 鏈接處於 半關閉(Half-close)狀態,即 客戶端 已經沒有數據要發送了,但 服務器 若發送數據,客戶端仍要接收。也就是說, 服務器 到 客戶端 這個方向的鏈接並未關閉,這個狀態可能會持續一段時間。

客戶端 收到來自 服務器 的確認後,就進入 FIN-WAIT-2(終止等待2) 狀態,等待 服務器 發出的鏈接釋放報文段。

第三次握手:若 服務器 已經沒有要向 客戶端 發送的數據,其應用進程就通知 TCP 釋放鏈接。這時 服務器發出的鏈接使用報文段必須使用 FIN = 1。現假設 服務器 的序號爲 w(在半關閉狀態 服務器 可能又發送了一些數據)。服務器還必須重複上次已發送過的確認號 ack = u + 1。這時 服務器 就進入 LAST-ACK (最後確認) 狀態,等待 客戶端 的確認。

第四次握手:客戶端 在收到 服務器 的鏈接釋放報文段後,必須對此發出確認。在確認報文段中把 ACK 置 1,確認號 ack = w + 1,而本身的序號是 seq = u + 1(根據 TCP 標準,前面發送過的 FIN 報文段要消耗一個序號)。而後進入到 TIME-WAIT(時間等待) 狀態。請注意,TCP 鏈接如今尚未釋放掉。必須通過 時間等待計時器(TIME-WAIT)設置的時間 2MSL 後,客戶端 才進入到 CLOSED 狀態。時間 MSL 叫作 最長報文段壽命,RFC 793 建議設爲 2 分鐘。

爲何 客戶端 在 TIME-WAIT 狀態必須等待 2MSL 的時間呢?

第一,爲了保證 客戶端 發送的最後一個 ACK 報文段可以到達 服務器。這個 ACK 報文段有可能丟失,於是使 服務器 收不到確認。服務器 會超時重傳這個 FIN + ACK 報文段,而 客戶端 就能在 2MSL 時間內收到這個重傳的報文段。接着 客戶端 重傳一次確認,從新啓動 2MSL 計時器。最後,客戶端 和 服務器 都能正常進入到 CLOSED 狀態。若是 客戶端 在 TIME-WAIT 狀態不等待一段時間,而是在發送完 ACK 報文段後當即釋放鏈接,那麼就沒法收到 服務器 重傳 的 FIN+ACK 報文段,於是也不會再發送一次確認報文段。這樣,服務器 就沒法按照正常步驟進入 CLOSED 狀態。

第二,防止「已失效的鏈接請求報文段」 出如今本次鏈接中。客戶端 在發送完最後一個 ACK 報文段後,再通過 2MSL,就可使本次鏈接持續的時間內所產生的全部報文段都從網絡中消失。這樣就可使下一個新的鏈接中不會出現這種舊的鏈接請求報文段。

若是已經創建了鏈接,可是客戶端忽然出現故障了怎麼辦?

TCP 設有一個 保活計時器。服務器每收到一次客戶的數據,就從新設置保活計時器,時間的設置一般是兩小時。若兩小時沒有收到客戶的數據,服務器就發送一個 探測報文段 ,之後則每隔 75 秒鐘發送一次。若一連發送 10 個探測報文段後仍無客戶的響應,服務器就認爲客戶端出了故障,接着就關閉這個鏈接。


參考:《計算機網絡》謝希仁 

相關文章
相關標籤/搜索