1. 程式人生 > 其它 >TCP 連線過程問題集

TCP 連線過程問題集

TCP的三次握手和四次分手

​ 我們知道TCP建立連線需要經過三次握手,而斷開連線需要經過四次分手,那三次握手和四次分手分別做了什麼和如何進行的。

三次握手

  1. 客戶端通過connect發起主動,向伺服器發出連線請求,請求中首部同步位 SYN = 1,同時選擇一個初始序號 sequence ,簡寫 seq = x。SYN 報文段不允許攜帶資料,只消耗一個序號。此時,客戶端進入SYN-SEND 狀態。
  2. 伺服器收到客戶端連線後,需要回復確認客戶端的報文段。在確認報文段中,把 SYN 和 ACK 位都置為 1 。確認號 ack = x + 1,同時也為自己選擇一個初始序號 seq = y。這個報文段也不能攜帶資料,但同樣要消耗掉一個序號。此時,TCP 伺服器進入 SYN-RECEIVED(同步收到)
    狀態。
  3. 客戶端在收到伺服器發出的響應後,還需要給出確認連線。確認連線中的 ACK 置為 1 ,序號為 seq = x + 1,確認號為 ack = y + 1。TCP 規定,這個報文段可以攜帶資料也可以不攜帶資料,如果不攜帶資料,那麼下一個資料報文段的序號仍是 seq = x + 1。這時,客戶端進入ESTABLISHED (已連線)狀態

四次揮手

  1. 客戶端停止傳送資料,主動關閉 TCP 連線。傳送 FIN 位,置為 1 ,不包含資料,假設此時序列號位 seq = u,此時客戶端主機進入FIN-WAIT-1(終止等待 1)階段。這表示主機沒有資料要傳送給服務端了;

  2. 伺服器主機接受到客戶端發出的報文段後,即發出確認應答報文,確認應答報文中 ACK = 1,生成自己的序號位 seq = v,ack = u + 1,

    然後伺服器主機就進入CLOSE-WAIT(關閉等待)狀態。客戶端主機收到服務端主機的確認應答後,即進入FIN-WAIT-2(終止等待2)的狀態。等待客戶端發出連線釋放的報文段。

  3. 服務端主機會發出斷開連線的報文段,報文段中 ACK = 1,序列號 seq = v,ack = u + 1,在傳送完斷開請求的報文後,服務端主機就進入了 LAST-ACK(最後確認)的階段。

  4. 客戶端收到服務端的斷開連線請求後,客戶端需要作出響應,客戶端發出斷開連線的報文段,在報文段中,ACK = 1, 序列號 seq = u + 1,因為客戶端從連線開始斷開後就沒有再發送資料,ack = v + 1,然後進入到TIME-WAIT(時間等待)

    狀態,請注意,這個時候 TCP 連線還沒有釋放。必須經過時間等待的設定,也就是2MSL後,客戶端才會進入CLOSED狀態,時間 MSL 叫做最長報文段壽命(Maximum Segment Lifetime)

  5. 服務端主要收到了客戶端的斷開連線確認後,就會進入 CLOSED 狀態。

TCP 連線的任意一方都可以發起關閉操作,只不過通常情況下發起關閉連線操作一般都是客戶端。然而,一些伺服器比如 Web 伺服器在對請求作出相應後也會發起關閉連線的操作。TCP 協議規定通過傳送一個 FIN 報文來發起關閉操作。

其他型別的開啟和關閉

TCP 半開啟

TCP 連線處於半開啟的這種狀態是因為連線的一方關閉或者終止了這個 TCP 連線卻沒有通知另一方。此時就認為這條連線處於半開啟狀態。這種情況發生在通訊中的一方處於主機崩潰的情況下,只要處於半連線狀態的一方不傳輸資料的話,那麼是無法檢測出來對方主機已經下線的。

另外一種處於半開啟狀態的原因是通訊的一方關閉了主機電源而不是正常關機。這種情況下會導致伺服器上有很多半開啟的 TCP 連線。

TCP 半關閉

既然 TCP 支援半開啟操作,那麼我們可以設想 TCP 也支援半關閉操作。同樣的,TCP 半關閉也並不常見。TCP 的半關閉操作是指僅僅關閉資料流的一個傳輸方向。兩個半關閉操作合在一起就能夠關閉整個連線。在一般情況下,通訊雙方會通過應用程式互相傳送 FIN 報文段來結束連線,但是在 TCP 半關閉的情況下,客戶端發起了 FIN 報文,要求主動斷開連線,伺服器收到 FIN 後,迴應 ACK ,由於此時發起半關閉的一方也就是客戶端仍然希望伺服器傳送資料,所以伺服器會繼續傳送資料,一段時間後伺服器傳送另外一條 FIN 報文,在客戶端收到 FIN 報文迴應 ACK 給伺服器後,斷開連線。

同時開啟和同時關閉

還有一種比較非常規的操作,這就是兩個應用程式同時主動開啟連線。雖然這種情況看起來不太可能,但是在特定的安排下卻是有可能發生的。我們主要講述這個過程。

同時開啟

通訊雙方都在收到對方報文前主動傳送了 SYN 報文,都在收到彼此的報文後回覆了一個 ACK 報文。

一個同時開啟過程需要交換四個報文段,比普通的三次握手增加了一個,由於同時開啟沒有客戶端和伺服器一說,所以這裡我用了通訊雙方來稱呼。

同時關閉

同時關閉過程中需要交換和正常關閉相同數量的報文段,只不過同時關閉不像四次揮手那樣順序進行,而是交叉進行的。

初始序列號

也許是我上面圖示或者文字描述的不專業,初始序列號它是有專業術語表示的,初始序列號的英文名稱是Initial sequence numbers (ISN),所以我們上面表示的 seq = v,其實就表示的 ISN。

在傳送 SYN 之前,通訊雙方會選擇一個初始序列號。初始序列號是隨機生成的,每一個 TCP 連線都會有一個不同的初始序列號。RFC 文件指出初始序列號是一個 32 位的計數器,每 4 us(微秒) + 1。因為每個 TCP 連線都是一個不同的例項,這麼安排的目的就是為了防止出現序列號重疊的情況。

當一個 TCP 連線建立的過程中,只有正確的 TCP 四元組和正確的序列號才會被對方接收。這也反應了 TCP 報文段容易被偽造的脆弱性,因為只要我偽造了一個相同的四元組和初始序列號就能夠偽造 TCP 連線,從而打斷 TCP 的正常連線,所以抵禦這種攻擊的一種方式就是使用初始序列號,另外一種方法就是加密序列號。