【面試】徹底理解 TCP 及面試常問

南望山下磚瓦工發表於2019-03-29

這個問題真的是爛大街了,但是真正問起來有很多細節的東西需要注意,被騰訊面試官問的我開始懷疑人生了。

計算機網路體系結構

在介紹 TCP/IP 之前需要簡單介紹計算機網路體系結構,當然這個也是面試中經常會問到的。

總的來說體系結構的劃分有三種:

  1. 五層協議
  • 應用層

為特定應用程式提供資料傳輸服務,例如 HTTP、SMTP、FTP、DNS 等,資料單位為報文(位於應用層的資訊分組)

  • 運輸層

提供的是程式間的通用資料傳輸服務,在應用程式端點之間傳送應用層報文。包括兩種協議:傳輸控制協議 TCP,提供面向連線、可靠的資料傳輸服務,資料單位為報文段(運輸層分組);使用者資料包協議 UDP,提供無連線、盡最大努力的資料傳輸服務,資料單位為使用者資料包。TCP 主要提供完整性服務,UDP 主要提供及時性服務。

  • 網路層

主機間提供資料傳輸服務,運輸層協議是為主機中的程式提供資料傳輸服務。網路層把運輸層傳遞下來的報文段或者使用者資料包封裝成分組。

  • 資料鏈路層

網路層針對的還是主機之間的資料傳輸,而主機之間可以有鏈路,鏈路層就是為相同鏈路的主機提供服務。資料鏈路層將網路層傳下來的分組封裝成幀

  • 物理層

考慮的是怎樣在傳輸媒體上傳輸資料位元流,而不是指具體的傳輸媒體。物理層的作用是儘可能遮蔽傳輸媒體和通訊手段的差異,使資料鏈路層感覺不到這些差異。

  1. OSI

相比於五層協議多了表示層和會話層,用途如下:

  • 表示層:資料壓縮、加密以及資料描述,這使得應用程式不必擔心在各臺主機中資料內部格式不同的問題
  • 會話層:建立及管理會話
  1. TCP/IP

只有四層,相當於五層協議中資料鏈路層和物理層合併為網路介面層。

TCP/IP

TCP 特性

  • TCP 是一種面向連線的、可靠的位元組流服務
  • 在一個 TCP 連線中,僅有兩方進行通訊,廣播和多播不能用於 TCP
  • TCP 使用校驗和,確認和重傳機制來保證可靠傳輸
  • TCP 給資料分節進行排序,並使用累積確認保證資料的順序不變和非重複
  • TCP 使用滑動視窗機制來實現流量控制,通過動態改變視窗的大小進行擁塞控制

注意: TCP 並不能保證資料一定會被接收方收到,因為這是不可能的,總會出現資料的丟失,只不過 TCP 能夠保證的是傳送的資料可以得到確認,就是說即使沒有到達,可以有重傳機制來保證,如果到達了還有確認機制來保證資料傳輸的正確性。因此準確的說 TCP 也不是 100% 可靠的協議,所能提供的是資料的可靠遞送或故障的可靠通知。

三次握手與四次揮手

下面為 TCP 狀態碼列表,以 S 指代伺服器,C 指代客戶端,S&C 表示兩者,S/C 表示兩者之一:

LISTEN S

伺服器等待從任意遠端TCP埠的連線請求。偵聽狀態。

SYN-SENT C

客戶在傳送連線請求後等待匹配的連線請求。通過connect()函式向伺服器發出一個同步(SYNC)訊號後進入此狀態。

SYN-RECEIVED S

伺服器已經收到併傳送同步(SYNC)訊號之後等待確認(ACK)請求。

ESTABLISHED S&C

伺服器與客戶的連線已經開啟,收到的資料可以傳送給使用者。資料傳輸步驟的正常情況。此時連線兩端是平等的。這稱作全連線。

FIN-WAIT-1 S&C

(伺服器或客戶)主動關閉端呼叫close()函式發出FIN請求包,表示本方的資料傳送全部結束,等待TCP連線另一端的ACK確認包或FIN&ACK請求包。

FIN-WAIT-2 S&C

主動關閉端在FIN-WAIT-1狀態下收到ACK確認包,進入等待遠端TCP的連線終止請求的半關閉狀態。這時可以接收資料,但不再傳送資料。

CLOSE-WAIT S&C

被動關閉端接到FIN後,就發出ACK以迴應FIN請求,並進入等待本地使用者的連線終止請求的半關閉狀態。這時可以傳送資料,但不再接收資料。

CLOSING S&C

在發出FIN後,又收到對方發來的FIN後,進入等待對方對己方的連線終止(FIN)的確認(ACK)的狀態。少見。

LAST-ACK S&C

被動關閉端全部資料傳送完成之後,向主動關閉端傳送FIN,進入等待確認包的狀態。

TIME-WAIT S/C

主動關閉端接收到FIN後,就傳送ACK包,等待足夠時間以確保被動關閉端收到了終止請求的確認包。【按照RFC 793,一個連線可以在TIME-WAIT保證最大四分鐘,即最大分段壽命(maximum segment lifetime)的2倍】

CLOSED S&C

完全沒有連線。

  1. 三次握手

三次握手協議指的是在傳送資料的準備階段,伺服器端和客戶端之間需要進行三次互動,詳細過程如下:

用三報文握手建立 TCP 連線

  • A 向 B 傳送請求報文,傳送包含一個 SYN 包,以及一個 seq 號,初始化為 x
  • B 接收到連線請求報文,如果同意連線,就會向 A 傳送確認報文,包括 SYN = 1,ACK = 1,確認號為 x + 1,而也會選擇一個隨機的序號 y
  • A 收到 B 的確認報文以後,還要向 B 發出確認,確認號為 y + 1,序號為 x + 1,B 收到以後就簡歷連線

三次握手原因:

第三次握手是為了防止失效的連線請求到達伺服器,讓伺服器錯誤開啟連線。客戶端傳送的連線請求如果在網路中滯留,那麼就會隔很長一段時間才能收到伺服器端的連線確認。而對於客戶端來說存在超時重傳機制,就是在超過一個重傳時間還沒有收到確認的話,就會重新請求連線,但是第一次傳送的滯留的連線請求還會到達伺服器,如果不進行三次握手,那麼伺服器就會開啟兩個連線,如果有三次握手客戶端會忽略伺服器之後傳送的對滯留連線請求的連線確認,不進行第三次握手,因此就不會再次開啟連線。

這裡可能涉及到 SYN 攻擊

  • 什麼是 SYN 攻擊?

在三次握手過程中,伺服器傳送 SYN-ACK 之後,收到客戶端的 ACK 之前的 TCP 連線稱為半連線(half-open connect)。此時伺服器處於 SYN_RCVD 狀態。當收到 ACK 後,伺服器才能轉入 ESTABLISHED 狀態。

SYN 攻擊指的是,攻擊客戶端在短時間內偽造大量不存在的 IP 地址,向伺服器不斷地傳送SYN包,伺服器回覆確認包,並等待客戶的確認。由於源地址是不存在的,伺服器需要不斷的重發直至超時,這些偽造 SYN 包將長時間佔用未連線佇列,正常的 SYN 請求被丟棄,導致目標系統執行緩慢,嚴重者會引起網路堵塞甚至系統癱瘓。

SYN 攻擊是一種典型的 DoS/DDoS 攻擊。

  • 如何檢測

檢測 SYN 攻擊非常的方便,當你在伺服器上看到大量的半連線狀態時,特別是源IP地址是隨機的,基本上可以斷定這是一次SYN攻擊。在 Linux/Unix 上可以使用系統自帶的 netstats 命令來檢測 SYN 攻擊。

netstat -n -p TCP | grep SYN_RECV
複製程式碼
  • 如何防禦

SYN攻擊不能完全被阻止,除非將TCP協議重新設計。我們所做的是儘可能的減輕SYN攻擊的危害,常見的防禦 SYN 攻擊的方法有如下幾種:

縮短超時(SYN Timeout)時間、增加最大半連線數、過濾閘道器防護、SYN cookies技術

  1. 四次揮手

建立一個連線需要三次握手,而終止一個連線要經過四次握手,這是由TCP的半關閉(half-close)造成的,詳細過程如下:

TCP 四次揮手示意圖

  • A 傳送連線釋放報文,FIN = 1
  • B 收到之後發出確認,此時 TCP 處於半關閉狀態,就是說 B 能向 A 傳送資料但是 A 不能向 B 傳送資料,這時候 B 會進入 CLOSE-WAIT 狀態,並會將未傳輸完畢的資料繼續傳送給客戶端。
  • 當 B 資料傳輸完成以後,會傳送連線釋放報文,FIN = 1,
  • A 收到之後會發出確認,並進入 TIME-WAIT 狀態,等待 2MSL(最大報文存活時間)後釋放連線,B 在收到 A 的確認之後會釋放連線

TIME-WAIT

客戶端收到服務端連線釋放 FIN = 1 以後,不是直接 CLOSED,還需要等待一個時間段 2MSL,這麼做有兩個原因:

  • 確保最後一個確認報文能夠到達,如果 B 沒有收到 A 傳送來的確認報文,那麼就會重新傳送連線釋放請求報文,A 等待一段時間就是為了防止這種情況的發生。
  • 等待一段時間是為了讓本連線持續時間內所產生的所有報文都從網路中小時,使得下一個新的連線不會出現舊的連線請求報文

參考資料

TCP三次握手及四次揮手詳細圖解

TCP 協議

傳輸控制協議 維基百科

TCP 百度百科

CS-Notes TCP 的三次握手

相關文章