在介紹三次握手和四次揮手以前,先來簡單認識一下 TCP 報文段的結構
TCP 首部包含如下內容,請留意其中的控制位,在三次握手和四次揮手過程當中會頻繁出現:面試
控制位 (Control Bits):在三次握手和四次揮手中會常常看到 SYN、ACK 和 FIN 的身影,一共有 6 個標誌位,它們表示的意義以下:算法
這個問題簡直太經典了,若是你在面試中只被問到了一個關於 TCP 的問題,那大機率就是關於三次握手的問題。TCP 的重要特性之一就是面向鏈接,鏈接雙方在發送數據以前必須經歷握手的階段,那具體的過程是怎樣的呢?先來看圖,你們最好能夠動手簡單畫畫這個圖,固然還有後文四次揮手的圖,幫助加深記憶。緩存
三次握手過程
如圖所示,雙方之間的三個藍色箭頭就表示了三次握手過程當中所發生的數據交換:服務器
常見面試題 1: TCP 創建鏈接爲何要三次握手而不是兩次?cookie
答:網上大多數資料對這個問題的回答只有簡單的一句:防止已過時的鏈接請求報文忽然又傳送到服務器,於是產生錯誤,這既不夠全面也不夠具體。下面給出比較詳細而全面的回答:網絡
在雙方兩次握手便可創建鏈接的狀況下,假設客戶端發送 A 報文段請求創建鏈接,因爲網絡緣由形成 A 暫時沒法到達服務器,服務器接收不到請求報文段就不會返回確認報文段,客戶端在長時間得不到應答的狀況下從新發送請求報文段 B,此次 B 順利到達服務器,服務器隨即返回確認報文並進入 ESTABLISHED 狀態,客戶端在收到 確認報文後也進入 ESTABLISHED 狀態,雙方創建鏈接並傳輸數據,以後正常斷開鏈接。此時姍姍來遲的 A 報文段纔到達服務器,服務器隨即返回確認報文並進入 ESTABLISHED 狀態,可是已經進入 CLOSED 狀態的客戶端沒法再接受確認報文段,更沒法進入 ESTABLISHED 狀態,這將致使服務器長時間單方面等待,形成資源浪費。併發
第一次握手:客戶端只是發送處請求報文段,什麼都沒法確認,而服務器能夠確認本身的接收能力和對方的發送能力正常;函數
第二次握手:客戶端能夠確認本身發送能力和接收能力正常,對方發送能力和接收能力正常;spa
第三次握手:服務器能夠確認本身發送能力和接收能力正常,對方發送能力和接收能力正常;操作系統
可見三次握手才能讓雙方都確認本身和對方的發送和接收能力所有正常,這樣就能夠愉快地進行通訊了。
TCP 實現了可靠的數據傳輸,緣由之一就是 TCP 報文段中維護了序號字段和確認序號字段,也就是圖中的 seq 和 ack,經過這兩個字段雙方均可以知道在本身發出的數據中,哪些是已經被對方確認接收的。這兩個字段的值會在初始序號值得基礎遞增,若是是兩次握手,只有發起方的初始序號能夠獲得確認,而另外一方的初始序號則得不到確認。
常見面試題2: TCP 創建鏈接爲何要三次握手而不是四次?
答:相比上個問題而言,這個問題就簡單多了。由於三次握手已經能夠確認雙方的發送接收能力正常,雙方都知道彼此已經準備好,並且也能夠完成對雙方初始序號值得確認,也就無需再第四次握手了。
常見面試題3: 有一種網絡攻擊是利用了 TCP 創建鏈接機制的漏洞,你瞭解嗎?這個問題怎麼解決?
答:在三次握手過程當中,服務器在收到了客戶端的 SYN 報文段後,會分配並初始化鏈接變量和緩存,並向客戶端發送 SYN + ACK 報文段,這至關因而打開了一個「半開鏈接 (half-open connection)」,會消耗服務器資源。若是客戶端正常返回了 ACK 報文段,那麼雙方能夠正常創建鏈接,不然,服務器在等待一分鐘後會終止這個「半開鏈接」並回收資源。這樣的機制爲 SYN洪泛攻擊 (SYN flood attack)提供了機會,這是一種經典的 DoS攻擊 (Denial of Service,拒絕服務攻擊),所謂的拒絕服務攻擊就是經過進行攻擊,使受害主機或網絡不能提供良好的服務,從而間接達到攻擊的目的。在 SYN 洪泛攻擊中,攻擊者發送大量的 SYN 報文段到服務器請求創建鏈接,可是卻不進行第三次握手,這會致使服務器打開大量的半開鏈接,消耗大量的資源,最終沒法進行正常的服務。
解決方法:SYN Cookies,如今大多數主流操做系統都有這種防護系統。SYN Cookies 是對 TCP 服務器端的三次握手作一些修改,專門用來防範 SYN 洪泛攻擊的一種手段。它的原理是,在服務器接收到 SYN 報文段並返回 SYN + ACK 報文段時,再也不打開一個半開鏈接,也不分配資源,而是根據這個 SYN 報文段的重要信息 (包括源和目的 IP 地址,端口號可一個祕密數),利用特定散列函數計算出一個 cookie 值。這個 cookie 做爲將要返回的SYN + ACK 報文段的初始序列號(ISN)。當客戶端返回一個 ACK 報文段時,服務器根據首部字段信息計算 cookie,與返回的確認序號(初始序列號 + 1)進行對比,若是相同,則是一個正常鏈接,而後分配資源並創建鏈接,不然拒絕創建鏈接。
這是 TCP 創建鏈接的特殊狀況,有時會出現兩臺機器同時執行主動打開的狀況,不過幾率很是小,這種狀況你們僅做了解便可。在這種狀況下就無所謂發送方和接收方了,雙放均可以稱爲客戶端和服務器,同時打開的過程以下:
同時打開的過程
如圖所示,雙方在同一時刻發送 SYN 報文段,並進入 SYN-SENT 狀態,在收到 SYN 後,狀態變爲 SYN-RECEIVED,同時它們都再發送一個 SYN + ACK 的報文段,狀態都變爲 ESTABLISHED,鏈接成功創建。在此過程當中雙方一共交換了4個報文段,比三次握手多一個。
創建一個鏈接須要三次握手,而終止一個鏈接要通過 4次握手。這由 TCP 的半關閉( half-close) 形成的。既然一個 TCP 鏈接是全雙工 (即數據在兩個方向上能同時傳遞), 所以每一個方向必須單獨地進行關閉。這原則就是當一方完成它的數據發送任務後就能發送一個 FIN 來終止這個方向鏈接。當一端收到一個 FIN,它必須通知應用層另外一端已經終止了數據傳送。理論上客戶端和服務器均可以發起主動關閉,可是更多的狀況下是客戶端主動發起。
四次揮手過程
四次揮手詳細過程以下:
常見面試題1: 爲何 TCP 關閉鏈接爲何要四次而不是三次?
答:服務器在收到客戶端的 FIN 報文段後,可能還有一些數據要傳輸,因此不能立刻關閉鏈接,可是會作出應答,返回 ACK 報文段,接下來可能會繼續發送數據,在數據發送完後,服務器會向客戶單發送 FIN 報文,表示數據已經發送完畢,請求關閉鏈接,而後客戶端再作出應答,所以一共須要四次揮手。
常見面試題2: 客戶端爲何須要在 TIME-WAIT 狀態等待 2MSL 時間才能進入 CLOSED 狀態?
答:按照常理,在網絡正常的狀況下,四個報文段發送完後,雙方就能夠關閉鏈接進入 CLOSED 狀態了,可是網絡並不老是可靠的,若是客戶端發送的 ACK 報文段丟失,服務器在接收不到 ACK 的狀況下會一直重發 FIN 報文段,這顯然不是咱們想要的。所以客戶端爲了確保服務器收到了 ACK,會設置一個定時器,並在 TIME-WAIT 狀態等待 2MSL 的時間,若是在此期間又收到了來自服務器的 FIN 報文段,那麼客戶端會從新設置計時器並再次等待 2MSL 的時間,若是在這段時間內沒有收到來自服務器的 FIN 報文,那就說明服務器已經成功收到了 ACK 報文,此時客戶端就能夠進入 CLOSED 狀態了。
以前在介紹 TCP 創建鏈接的時候會有一種特殊狀況,那就是同時打開,與之對應地, TCP 關閉時也會有一種特殊狀況,那就是同時關閉,這種狀況僅做了解便可,流程圖以下:
同時關閉過程
這種狀況下,雙方應用層同時發出關閉命令,這將致使雙方各發送一個 FIN,兩端均從 ESTABLISHED 變爲 FIN_WAIT_1,兩個 FIN 通過網絡傳送後分別到達另外一端。收到 FIN 後,狀態由 FIN_WAIT_1 變遷到 CLOSING,併發送最後的 ACK,當收到最後的 ACK 時,爲確保對方也收到 ACK,狀態變化爲 TIME_WAIT,並等待 2MSL 時間,若是一切正常,隨後會進入 CLOSED 狀態。
本文經過圖解的方式爲你們詳細介紹了 TCP 三次握手和四次揮手的過程,只要把這幾張圖弄明白,再碰到相關的面試題就遊刃有餘了。