面試官問我TCP三次握手和四次揮手,我真的是

候選者面試官你好,請問面試可以開始了嗎

面試官:嗯,開始吧

面試官今天來聊聊TCP吧,TCP的各個狀態還有印象嗎?

候選者:還有些許印象的,要不我就來簡單說下TCP的三次握手和四次揮手的流程吧

候選者:說完這兩個流程,就能把TCP的狀態給涵蓋上了

面試官:可以吧

候選者:在說TCP的三次握手和四次揮手之前,我先給你畫下TCP的頭部格式唄(:

候選者:對於TCP三次握手和四次揮手,我們最主要的就是關注TCP頭部的序列號、確認號以及幾個標記位(SYN/FIN/ACK/RST)

候選者:序列號:在初次建立連接的時候,客戶端和服務端都會爲「本次的連接」隨機初始化一個序列號。(縱觀整個TCP流程中,序列號可以用來解決網絡包亂序的問題)

候選者:確認號:該字段表示「接收端」告訴「發送端」對上一個數據包已經成功接收(確認號可以⽤來解決網絡包丟失的問題)

候選者:而標記位就很好理解啦。SYN爲1時,表示希望創建連接。ACK爲1時,確認號字段有效。FIN爲1時,表示希望斷開連接。RST爲1時,表示TCP連接出現異常,需要斷開。

候選者:下面就先從三次握手開始吧,期間我也會在三次握手中涉及到的TCP狀態也說下的。

候選者:TCP三次握手的過程其實就是在:確認通信雙方(客戶端和服務端)的序列號

候選者:它的過程是這樣的

候選者:在最開始的時候,客戶端和服務端都處於 CLOSE 狀態

候選者:服務器主動監聽某個端口,處於 LISTEN 狀態

候選者:客戶端會隨機生成出序列號(這裏的序列號一般叫做client_isn),並且把標誌位設置爲SYN(意味着要連接),然後把該報文發送給服務端

候選者:客戶端發送完SYN報文以後,自己便進入了 SYN_SEND 狀態

候選者:服務端接收到了客戶端的請求之後,自己也初始化對應的序列號(這裏的序列號一般叫做 server_isn)

候選者:在「確認號」字段裏填上client_isn + 1(相當於告訴客戶端,已經收到了發送過來的序列號了) ,並且把 SYN 和 ACK 標記位都點亮(置爲1)

候選者:把該報文發送客戶端,服務端的狀態變成 SYN-REVD 狀態

候選者:客戶端收到服務端發送的報文後,就知道服務端已經接收到了自己的序列號(通過確認號就可以知道),並且接收到了服務端的序列號(server_isn)

候選者:此時,客戶端需要告訴服務端自己已經接收到了他發送過來的序列號,所以在「確認號」字段上填上server_isn+1,,並且標記位 ACK 爲1

候選者:客戶端在發送報文之後,進入 ESTABLISHED 狀態,而服務端接收到客戶端的報文之後,也進入 ESTABLISHED 狀態

候選者:這就是三次握手的過程以及涉及到的TCP狀態

候選者:總結下來,就是雙方都把自身的序列號發給對方,看對方能不能接收到。如果「確認可以」,那就可以正常通信。(三次握手這個過程就可以看到雙方都有接收和發送的能力)

面試官那兩次握手行嗎?

候選者:兩次握手只能保證客戶端的序列號成功被服務端接收,而服務端是無法確認自己的序列號是否被客戶端成功接收。所以是不行的(:

面試官瞭解了,那我想問問序列號爲什麼是隨機的?以及序列號是怎麼生成的?

候選者:一方面爲了安全性(隨機ISN能避免非同一網絡的攻擊),另一方面可以讓通信雙方能夠根據序號將「不屬於」本連接的報文段丟棄

候選者:序列號怎麼生成的?這...隨便猜下就應該跟「時鐘」和TCP頭部的某些屬性做運算生成的吧,類似於雪花算法(:具體我忘了。

面試官既然網絡是不可靠的,那建立連接不是會經過三次握手嗎?那要是在中途丟了,怎麼辦?

候選者:假設第一個包丟了,客戶端發送給服務端的 SYN 包丟了(簡而要之就是服務端沒接收到客戶端的SYN包)

候選者:客戶端遲遲收不到服務端的ACK包,那會週期性超時重傳,直到收到服務端的ACK

候選者:假設第二個包丟了,服務端發送的SYN+ACK包丟了(簡而要之就是客戶端沒接收到服務端的SYN+ACK包)

候選者:服務端遲遲收不到客戶端的ACK包,那會週期性超時重傳,直到收到客戶端的ACK

候選者:假設第三個包丟了(ACK包),客戶端發送完第三個包後單方面進入了 ESTABLISHED 狀態,而服務端也認爲此時連接是正常的,但第三個包沒到達服務端

候選者:一、如果此時客戶端與服務端都還沒數據發送,那服務端會認爲自己發送的SYN+ACK的包沒發送至客戶端,所以會超時重傳自己的SYN+ACK包

候選者:二、如果這時候客戶端已經要發送數據了,服務端接收到了ACK + Data數據包,那自然就切換到 ESTABLISHED 狀態下,並且接收客戶端的Data數據包

候選者:三、如果此時服務端要發送數據了,但發送不了,會一直週期性超時重傳SYN + ACK,直到接收到客戶端的ACK包

面試官嗯,是不是要講下四次揮手了?

候選者:嗯,在建立完連接之後,客戶端和服務端雙方都處於 ESTABLISHED 狀態狀態

候選者:斷開連接雙方都有權利的,下面我還是以客戶端主動斷開爲例好啦。

候選者:客戶端打算關閉連接,會發 FIN 報文給服務端(其實就是把標誌位 FIN 點亮),客戶端發送完之後,就進入FIN_WAIT_1狀態

候選者:服務端收到 FIN 報文之後,回覆 ACK 報文給客戶端(表示已經收到了),服務端發送完之後,就進入 CLOSE_WAIT 狀態

候選者:客戶端接收到服務端的 ACK 報文,就進入了 FIN_WAIT_2 狀態

候選者:這時候,服務器可能還有數據要發送給客戶端,等服務端確認自己已經沒有數據返回給客戶端之後,就發送FIN報文給客戶端了,自己進入 LAST_ACK 狀態

候選者:客戶端收到服務端的FIN報文之後,迴應ACK報文,自己進入 TIME_WAIT 狀態

候選者:服務端收到客戶端的ACK報文之後,服務端就進入 CLOSE 狀態

候選者:客戶端在TIME_WAIT等到2MSL,也進入了 CLOSE 狀態

候選者:四次揮手的流程到這裏就結束了,結合三次握手,TCP的各個狀態也已經說完了。

面試官:嗯嗯,剛聊完四次揮手嘛,那你覺得爲什麼是四次呢?

候選者:其實很好理解,當客戶端第一次發送 FIN 報文之後,只是代表着客戶端不再發送數據給服務端,但此時客戶端還是有接收數據的能力的。而服務端收到FIN報文的時候,可能還有數據要傳輸給客戶端,所以只能先回復 ACK給客戶端

候選者:等到服務端不再有數據發送給客戶端時,才發送 FIN 報文給客戶端,表示可以關閉了。

候選者:所以,一來一回就四次了。

面試官從四次揮手的流程上來看,有個 TIME_WAIT 狀態,你知道這個狀態幹什麼用的嗎?(等待 2MSL)

候選者:主要有兩個原因吧。1.保證最後的 ACK 報文 「接收方」一定能收到(如果收不到,對方會 重發 FIN 報文)2. 確保在創建新連接時,先前網絡中殘餘的數據都丟失了

候選者:其實也比較好理解的。就正如我們重啓服務器一樣,會先優雅關閉各種資源,再留有一段時間,希望在這段時間內,資源是正常關閉的,這樣重啓服務器(或者發佈)就基本認爲不會影響到線上運行了。

面試官假設 TIME_WAIT 狀態多過會有什麼危害?怎麼解決呢?

候選者:從流程上看, TIME_WAIT 狀態 只會出現在 主動發起 關閉連接的一方。危害就是會佔用內存資源和端口唄(畢竟在等待嘛),解決的話,有Linux參數可以設置,具體忘了額。

面試官:今天最後再問個問題吧,我們常說TCP連接,那這個連接到底是什麼?你是怎麼理解的?

候選者:其實從三次握手可以發現的是,TCP建立連接無非就是交換了雙方的狀態(比如序列號)。然後就沒有然後了...連接本質上「只是互相維持一個狀態,有連接特性」

面試官:好吧。

歡迎關注我的微信公衆號【Java3y】來聊聊Java面試,對線面試官系列持續更新中!

【對線面試官+從零編寫Java項目】 持續高強度更新中!求star

原創不易!!求三連!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章