TCP三次握手,握的是啥?
目錄
前言
先要弄清楚兩個概念
抓包分析
建立連接過程中的Sequence number
數據傳輸過程中的Sequence number
為什么TCP建立連接不是兩次握手也不是四次握手?
補充閱讀
前言
最近在知乎上看到一個問題——TCP為什么是三次握手,而不是兩次或四次?這個問題我原先也發過博客,之前我的回答是:為了防止兩次握手情況下已失效的連接請求報文段突然有傳送到服務端,而產生了錯誤(主要是參考謝希仁版的《計算機網絡》)。以及四次握手不能有效的增加TCP連接的安全性,反而讓客戶端等待的時間變長。但是在看了車小胖的回答后,我才真的理解了為什么TCP連接要采用三次握手以及三次握手握了哪些信息。以下會有很多他所舉得例子,我也會抓一些包向大家展示三次握手中的序號和確認號的變化。而謝希仁版的《計算機網絡》給我們的例子也沒有問題,只是問題的切入點不一樣。
?
先要弄清楚兩個概念
(1) 序號:占4個字節。TCP是面向字節流的,所以TCP連接中傳送的數據流中的每一個字節都編上一個序號。序號字段的值則指的是本報文段所發送的數據的第一個字節的序號。例如,一個報文段的序號字段值是200,攜帶的數據總共有100字節,表明這個報文段的數據的最后一個字節的序號是299,所以下一個報文段的數據序號應從300開始。
(2) 確認號:占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的確認才可以發送數據。
總結
以上是生活随笔為你收集整理的TCP三次握手,握的是啥?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Raft 论文翻译
- 下一篇: 红黑树(RB-Tree)比AVL强在哪?