TCP 的 三次握手 四次握手

@L發表於2019-04-24

解釋 

  • 同步 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 報文段。


TCP 的 三次握手 四次握手

最初,客戶端和伺服器的 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 (已建立連線) 狀態。

通過這樣的三次握手,客戶端與伺服器端建立可靠的雙工的連線,開始傳送資料。三次握手的主要目的是保證連線是雙工的,可靠更多是通過重傳機制來保證的。

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

主要是為了防止已失效的連線請求報文段突然又傳到了 伺服器,因而產生錯誤。 

現假定出現一種異常情況,即 客戶端 發出的第一個連線請求報文段並沒有丟失,而是在某些網路結點長時間滯留了,以致延誤到連線釋放以後的某個時間才到達 伺服器。本來這是一個早已失效的報文段。但 伺服器 收到此失效的連線請求報文段後,就誤認為是 客戶端 又發出一次新的連線請求。於是就向 客戶端 發出確認報文段,同意建立連線。假定不採用報文握手,那麼只要 伺服器發出確認,新的連線就建立了。由於現在 客戶端 並沒有發出建立連線的請求,因此不會理睬 伺服器 的確認,也不會向 伺服器 傳送資料。但是 伺服器 卻以為新的運輸連線已經建立了,並一直等待 客戶端 發來資料。伺服器 的許多資源就這樣白白浪費了。 採用三次報文握手的辦法,可以防止上述現象的發生。假如在剛才的異常情況下,客戶端 不會像 伺服器 的確認發出確認。伺服器 由於收不到確認,就知道 客戶端 並沒有要求建立連線。

四報文握手

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


TCP 的 三次握手 四次握手

第一次握手 : 客戶端 的應用程式先向其 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 個探測報文段後仍無客戶的響應,伺服器就認為客戶端出了故障,接著就關閉這個連線。


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


相關文章