筆記 | 面試又掛了,只因問了:TCP三次握手和四次揮手
面試官:跟我講講TCP的三次握手和四次揮手流程,爲什麼是三次握手或四次揮手?
面試者:額......不太記得了.....gg..
在前面的文章知道, 《TCP與UDP的區別 》 ,到 《TCP是如何保證可靠性 》 。那麼接下來就是TCP的核心了,即TCP的可靠性依賴其:三次握手和四次揮手。
先思考下這三個面試題:
1、TCP 爲什麼三次握手而不是兩次握手?
2、爲什麼連接的時候是三次握手,關閉的時候卻是四次握手?
3、爲什麼TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?
在TCP/IP協議中,TCP協議提供可靠的連接服務,連接是通過三次握手進行初始化的。三次握手的目的是同步連接雙方的序列號和確認號並交換 TCP窗口大小信息。
tcp三次握手和四次揮手交互圖:
三次握手:
-
第一次握手:建立連接。客戶端發送連接請求報文段,將 SYN 位置爲1, Sequence Number 爲x;然後,客戶端進入 SYN_SEND 狀態,等待服務器的確認;
-
第二次握手:服務器收到 SYN 報文段。服務器收到客戶端的 SYN 報文段,需要對這個 SYN 報文段進行確認,設置 Acknowledgment Number 爲x+1( Sequence Number +1);同時,自己自己還要發送 SYN 請求信息,將 SYN 位置爲1, Sequence Number 爲y;服務器端將上述所有信息放到一個報文段(即 SYN+ACK 報文段)中,一併發送給客戶端,此時服務器進入 SYN_RECV 狀態;
-
第三次握手:客戶端收到服務器的 SYN+ACK 報文段。然後將 Acknowledgment Number 設置爲y+1,向服務器發送 ACK 報文段,這個報文段發送完畢以後,客戶端和服務器端都進入 ESTABLISHED 狀態,完成TCP三次握手。
四次揮手:
-
第一次揮手:主機1(可以使客戶端,也可以是服務器端),設置 Sequence Number 和 Acknowledgment Number ,向主機2發送一個 FIN 報文段;此時,主機1進入 FIN_WAIT_1 狀態;這表示主機1沒有數據要發送給主機2了;
-
第二次 揮手 :主機2收到了主機1發送的 FIN 報文段,向主機1回一個 ACK 報文段, Acknowledgment Number 爲 Sequence Number 加1;主機1進入 FIN_WAIT_2 狀態;主機2告訴主機1,我“同意”你的關閉請求;
-
第三次 揮手 :主機2向主機1發送 FIN 報文段,請求關閉連接,同時主機2進入 LAST_ACK 狀態;
-
第四次 揮手 :主機1收到主機2發送的 FIN 報文段,向主機2發送 ACK 報文段,然後主機1進入 TIME_WAIT 狀態;主機2收到主機1的 ACK 報文段以後,就關閉連接;此時,主機1等待2MSL後依然沒有收到回覆,則證明Server端已正常關閉,那好,主機1也可以關閉連接了。
三次握手可以簡單通俗理解爲:
1)A要跟B聊天,問B在嗎(收到了嗎)?(SYN)
2)B收到A,B回覆A說收到了,那我們開始吧。(ACK+SYN)
3)A收到B的回覆,A:那我們開始聊天(數據傳輸)。(ACK)
四次揮手可以簡答理解爲:
1)A跟B說,我要停止聊天了,你(B)還在嗎?準備中斷聊天了(FIN)
2)B收到A的消息,B回覆A說:我在。(ACK)
3)B再發一條消息給A說,A你可以停止了。(FIN)
4)A收到B說可以停止發消息了,A回覆B說:收到!(ACK)
1、TCP 爲什麼三次握手而不是兩次握手?
爲了實現可靠數據傳輸,TCP 協議的通信雙方,都必須維護一個序列號,以標識發送出去的數據包中,哪些是已經被對方收到的。三次握手的過程即是通信雙方相互告知序列號起始值, 並確認對方已經收到了序列號起始值的必經步驟。如果只是兩次握手,至多隻有連接發起方的起始序列號能被確認,另一方選擇的序列號則得不到確認。
2、爲什麼連接的時候是三次握手,關閉的時候卻是四次握手?
答:因爲當Server端收到Client端的SYN連接請求報文後,可以直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連接時,當Server端收到FIN報文時,很可能並不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。只有等到我Server端所有的報文都發送完了,我才能發送FIN報文,因此不能一起發送。故需要四步握手。
3、爲什麼TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?
答:雖然按道理,四個報文都發送完畢,我們可以直接進入CLOSE狀態了,但是我們必須假象網絡是不可靠的,有可能最後一個ACK丟失。所以TIME_WAIT狀態就是用來重發可能丟失的ACK報文。
文章關聯→→:
筆記系列↓↓↓:
筆記 | 併發編程的三大挑戰
參考: http://www.jellythink.com/archives/705