TCP三次握手,握的是啥?

目錄

前言

先要弄清楚兩個概念

抓包分析

建立連接過程中的Sequence number

數據傳輸過程中的Sequence number

爲什麼TCP建立連接不是兩次握手也不是四次握手?

補充閱讀


前言

最近在知乎上看到一個問題——TCP爲什麼是三次握手,而不是兩次或四次?這個問題我原先也發過博客,之前我的回答是:爲了防止兩次握手情況下已失效的連接請求報文段突然有傳送到服務端,而產生了錯誤(主要是參考謝希仁版的《計算機網絡》)以及四次握手不能有效的增加TCP連接的安全性,反而讓客戶端等待的時間變長。但是在看了車小胖的回答後,我才真的理解了爲什麼TCP連接要採用三次握手以及三次握手握了哪些信息。以下會有很多他所舉得例子,我也會抓一些包向大家展示三次握手中的序號和確認號的變化。而謝希仁版的《計算機網絡》給我們的例子也沒有問題,只是問題的切入點不一樣。

 

先要弄清楚兩個概念

()序號:佔4個字節。TCP是面向字節流的,所以TCP連接中傳送的數據流中的每一個字節都編上一個序號。序號字段的值則指的是本報文段所發送的數據的第一個字節的序號。例如,一個報文段的序號字段值是200,攜帶的數據總共有100字節,表明這個報文段的數據的最後一個字節的序號是299,所以下一個報文段的數據序號應從300開始。

()確認號:佔4個字節,是期望收到對方的下一個報文段的數據的第一個字節的序號。若確認號爲N,表明前N-1的所有數據都已經正確接收。例如,B正確的收到了A發送過來的一個報文段,其序號字段是指501,而數據長度是200字節(序號501~700),表明B正確的收到了A發送的序號700之前的數據。因此B希望收到A的下一個數據序號是701,所以B在發送給A的確認報文段中應把確認號設置成701。

TCP可靠傳輸的精髓:TCP連接的一方A,操作系統動態隨機選取一個32位長的序列號(Initial Sequence Number),假設A的初始序列號爲1000,以該序列號爲起始點,對自己將要發送的每個字節的數據進行編號,1000,1001,1002,1003…,並把自己的初始序列號ISN告訴B,讓B有一個思想準備,什麼樣編號的數據是合法的,什麼編號是非法的,比如編號900就是非法的,同時B還可以對A每一個編號的字節數據進行確認。如果A收到B確認編號爲2000,則意味着字節編號爲1000-1999,共1000個字節已經安全到達。

同理B也是類似的操作,假設B的初始序列號ISN爲2000,以該序列號爲原點,對自己將要發送的每個字節的數據進行編號,2000,2001,2002,2003…,並把自己的初始序列號ISN告訴A,以便A可以確認B發送的每一個字節。如果B收到A確認編號爲4000,則意味着字節編號爲2000-3999,共2000個字節已經安全到達。

 

一句話概括,TCP連接握手,握的是啥?

通信雙方數據的序列號的起始點!

 

抓包分析

建立連接過程中的Sequence number

圖中的[1687]和[1688]是三次握手中的後兩步。從[1687]這個報文可以看到Sequence number的值爲0,但是下方相應報文段的內容是[7f  a6  f7  31]。

 

[1688]的Sequence number值爲1,但是下方相應報文段的內容是[12  2d  d7  1d](起始點)。

 

[8197]發送的確認報文Sequence number爲10147,即有[12  2d  fe  bf](65215) - [12  2d  d7  1d](55069) = 10147 - 1。這說明在三次握手的過程中,通信雙方就將自己的序號的起始點告知給了對方,並且對方將這個數字記錄了下來,用於之後的通信。此時報文段中的實際值不代表傳輸過程中的序號值的真實含義。

 

爲什麼TCP在建立連接的時候不能每次選擇相同的、固定的初始序號?

答:(1)假如A和B頻繁地建立連接,傳送一些TCP報文段後再釋放連接,然後又不斷的建立新的連接、傳送報文段和釋放連接。

(2)假如每一次建立連接時,主機A都選擇相同的、固定的初始序號,如1。

(3)若主機A發送出的某些TCP報文段在網絡中會滯留較長的時間,以致造成主機A超時重傳這些TCP報文段。

(4)若有一些在網絡中滯留時間較長的TCP報文段最後終於到達了主機B,但這時傳送該報文段的那個連接早已釋放了,而在到達主機B時的TCP連接是一條新的TCP連接。

以上這些情況可能會導致在新的TCP連接中的主機B有可能會接收在舊的連接傳送的、已經沒有意義的、過時的TCP報文段(因爲這個TCP報文段的序號有可能正好處於新的連接所使用的序號範圍內)。因爲必須使得遲到的TCP報文段的序號不在新的連接中使用的序號範圍內。所以,TCP在建立新的連接時所選擇的初始序號一定要和前面的一些連接所使用過的序號不一樣。因此,不同的TCP連接不能使用相同的初始序號。

 

數據傳輸過程中的Sequence number

以下用A代表客戶端,B代表服務器。

[8197]A->B  Seq = 10147  Ack = 10391980  Len = 0   沒有傳輸數據,希望下一個收到的報文段的序號爲10391980。

[8198]B->A  Seq = 10391980  Ack = 10147  Len = 2800   因爲[8197]沒有數據,所以B希望收到的序號還是10147。此次B發送的數據從序號10391980開始,共2800個數據。

[8199]A->B  Seq = 10147  Ack = 10394780  Len = 0   沒有傳輸數據,希望下一個收到的報文段的序號爲10394780(10391980+2800)。

[8200]B->A  Seq = 10394780  Ack = 10147  Len = 1400   因爲[8199]沒有數據,所以B希望收到的序號還是10147。此次B發送的數據從序號10394780開始,共1400個數據。

[8201]B->A  Seq = 10396180  Ack = 10147  Len = 1400   此次B發送的數據從序號10396180開始,共1400個數據。

[8202]A->B  Seq = 10147  Ack = 10397580  Len = 0   確認號10397580 = 10396180 + 1400表明[8201]之前的數據已經正確接收了。

 

爲什麼TCP建立連接不是兩次握手也不是四次握手?

弄懂了TCP握手握的是什麼後,再來分析握幾次。

四次握手的過程:

1.1 A 發送同步信號SYN + A's Initial sequence number

1.2 B 確認收到A的同步信號,並記錄A's ISN 到本地,命名 B's ACK sequence number

1.3 B發送同步信號SYN + B's Initial sequence number 

1.4 A確認收到B的同步信號,並記錄B's ISN 到本地,命名 A's ACK sequence number並返回ACK。

很顯然1.2和1.3 這兩個步驟可以合併,只需要三次握手,可以提高連接的速度與效率。

 

如果A發給B的確認丟了,該如何?A會超時重傳這個ACK嗎?

答:A不會超時重傳,因爲TCP不會爲沒有數據的ACK超時重傳。處理方法是:B如果沒有收到A的ACK,會超時重傳自己的SYN同步信號,直到收到A的ACK爲止。

 

二次握手的過程:

2.1 A 發送同步信號SYN + A's Initial sequence number

2.2 B發送同步信號SYN + B's Initial sequence number + B's ACK sequence number

這裏有一個問題,A與B就A的初始序列號達成了一致,這裏是1000。但是B無法知道A是否已經接收到自己的同步信號,如果這個同步信號丟失了,A和B就B的初始序列號將無法達成一致。

於是TCP的設計者將SYN這個同步標誌位SYN設計成佔用一個字節的編號(FIN標誌位也是),既然是一個字節的數據,按照TCP對有數據的TCP segment 必須確認的原則,所以在這裏A必須給B一個確認,以確認A已經接收到B的同步信號。

 

補充閱讀

三次握手中的第三個包丟失,即A發給B的ACK中途被丟,沒有到達B,會有什麼情況?

A發完ACK,單方面認爲TCP爲 Established狀態,而B顯然認爲TCP爲Active狀態:

a. 假定此時雙方都沒有數據發送,B會週期性超時重傳,直到收到A的確認,收到之後B的TCP 連接也爲 Established狀態,雙向可以發包。

b. 假定此時A有數據發送,B收到A的 Data + ACK,自然會切換爲established 狀態,並接受A的Data。

c. 假定B有數據發送,數據發送不了,會一直週期性超時重傳SYN + ACK,直到收到A的確認纔可以發送數據。

發佈了77 篇原創文章 · 獲贊 179 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章