一、OSI 參考模型與 TCP/IP 參考模型#
如圖所示,OSI 參考模型為 7 層模型,從上到下依次為應用層、表示層、會話層、傳輸層、網絡層、數據鏈路層及物理層,TCP/IP 模型是在 OSI 參考模型的基礎上做了一定的精簡,形成一個 4 層模型。在層次關係上,兩者都採用了分層體系結構,都是對等的層間通信,不同之處在於 TCP/IP 參考模型比 OSI 參考模型層次更清晰簡練,在功能上,兩者差別不大,都是為了實現兩個或多個終端之間的通信。
二、TCP 通信位於網絡模型的哪一層?#
TCP(Transmission Control Protocol)是一種面向連接的、可靠的、基於字節流的傳輸層通信協議,無論是 OSI 參考模型,還是 TCP/IP 參考模型,TCP 都位於傳輸層,TCP 是為了在不可靠的互聯網絡上提供可靠的端到端字節流而專門設計的一個傳輸協議。
三、如何理解面向連接、可靠、字節流?#
-
面向連接:意味著 TCP 是點對點之間的通信,不能像 UDP 那樣可以一個主機同時向多個主機發送消息,也就是無法實現一對多的情形。
-
可靠的:無論網絡鏈路如何變化,TCP 都可以保障報文能夠到達接收端。
-
字節流:基於字節流,意味著無論我們消息有多大都可以進行傳輸。並且消息是有序的,當前一個消息沒有收到的時候,即使它先收到了後面的字節已經收到,那麼也不能扔給應用層去處理,同時對重複的報文會自動丟棄。
四、為什麼需要 TCP 協議?#
因為 IP 層是不可靠的,它不保證網絡包的一定交付、不保證按序交付、也不保證完整交付。因此如果需要保證網絡數據包的可靠性,就必須要通過上層即傳輸層的 TCP 協議來保證。
五、TCP 與 UDP 之間區別及聯繫?#
TCP 與 UDP 都屬於傳輸層協議,區別如下:
- 連接機制
TCP 是面向連接的傳輸層協議
UDP 是不需要連接 - 服務對象
TCP 是一對一的兩點服務
UDP 支持一對一、一對多、多對多 - 可靠性
TCP 保證數據不丟失、不重複、按需到達
UDP 是盡最大努力交付,不保證交付數據 - 擁塞控制、流量控制
TCP 有擁塞控制和流量控制機制
UDP 則沒有擁塞控制和流量控制機制
六、TCP 首部報文分析#
TCP 的首部至少占用 20 個字節,包含的內容有源端口號、目標端口號、序列號、應答號、控制位、校驗和等,具體如下所示:
七、簡要說明 TCP 三次握手#
- 伺服器與客戶端均處於 CLOSE 狀態
- 伺服器先主動監聽某端口,處理 LISTEN 狀態
- 客戶端發送 SYN 報文,seq=x,SYN=1
- 伺服器回覆 SYN+ACK 報文,seq=y,ack=x+1,SYN=1,ACK=1
- 客戶端回覆 ACK 報文,ack=y+1,ACK=1
八、簡要說明 TCP 四次揮手#
伺服器與客戶端均處於 ESTABLISHED 狀態
- 客戶端打算關閉連接,發送一個 FIN 報文,進入 FIN_WAIT_1 狀態。
- 伺服器回覆 ACK 報文,進入 CLOSED_WAIT 狀態。
- 客戶端收到 ACK 應答報文後,進入 FIN_WAIT_2 狀態。
- 伺服器處理完數據後,向客戶端發送 FIN 報文,進入 LAST_ACK 狀態。
- 客戶端回覆一個 ACK 應答報文,之後進入 TIME_WAIT 狀態
- 伺服器收到 ACK 應答報文後,進入了 CLOSE 狀態,伺服器完成連接的關閉。
- 客戶端在經過 2MSL 一段時間後,自動進入 CLOSE 狀態,客戶端也完成連接的關閉。
九、TCP 握手為什麼剛好是三次?#
TCP 建立連接時,通過三次握手能防止歷史連接的建立,能減少雙方不必要的資源開銷,能幫助雙方同步初始化序列號。序列號能夠保證數據包不重複、不丟棄和按序傳輸。
不使用「兩次握手」和「四次握手」的原因:
- 兩次握手:無法防止歷史連接的建立,會造成雙方資源的浪費,也無法可靠的同步雙方序列號;
- 四次握手:三次握手就已經理論上最少可靠連接建立,所以不需要使用更多的通信次數。
十、TCP 揮手為什麼需要四次?#
回顧下四次揮手雙方發 FIN 包的過程,就能理解為什麼揮手需要四次:
- 關閉連接時,客戶端向伺服器發送 FIN 時,僅僅表示客戶端不再發送數據了但是還能接收數據。
- 伺服器收到客戶端的 FIN 報文時,先回一個 ACK 應答報文,而伺服器可能還有數據需要處理和發送,等伺服器不再發送數據時,才發送 FIN 報文給客戶端來表示同意現在關閉連接。
- 由於伺服器通常需要等待完成數據的發送和處理,所以伺服器的 ACK 和 FIN 一般都會分開發送,從而比三次握手導致多了一次。
十一、四次揮手中的 TIME_WAIT 狀態?#
首先要明確一點:主動關閉連接的一方,才會有 TIME_WAIT 狀態。
之所以需要 TIME_WAIT 狀態,主要是兩個原因:
- 防止相同的端口重新連接時,伺服器收到的是停留在網絡間的數據包
- 保證被動關閉連接的一方能被正確的關閉,即保證最後的 ACK 能讓被動關閉方接收,從而幫助其正常關閉
十二 、為什麼 TIME_WAIT 時間為 2MSL?#
MSL 是 Maximum Segment Lifetime,報文最大生存時間,它是任何報文在網絡上存在的最長時間,超過這個時間報文將被丟棄。比如如果被動關閉方沒有收到斷開連接的最後的 ACK 報文,就會觸發超時重發 FIN 報文,另一方接收到 FIN 後,會重發 ACK 給被動關閉方,一來一去正好 2 個 MSL。
2MSL 的時間是從客戶端接收到 FIN 後發送 ACK 開始計時的。如果在 TIME-WAIT 時間內,因為客戶端的 ACK 沒有傳輸到伺服器,客戶端又接收到了伺服器重發的 FIN 報文,那麼 2MSL 時間將重新計時。在 Linux 系統中,2MSL 默認值是 60 秒。
十三、什麼是 TCP 的保活機制?#
定義一個時間段,在這個時間段內,如果沒有任何連接相關的活動,TCP 保活機制會開始作用,每隔一個時間間隔,發送一個探測報文,該探測報文包含的數據非常少,如果連續幾個探測報文都沒有得到響應,則認為當前的 TCP 連接已經死亡,系統內核將錯誤信息通知給上層應用程序。
十四、已經建立連接,客戶端故障怎麼辦?#
這種情況就會觸發 TCP 的保活機制,對應的參數包括保活時間、保活探測的次數、保活探測的時間間隔,其中保活時間默認為 7200 秒,保活探測次數為 9,保活探測時間間隔為 75 秒。
也就意味著,如果客戶端突然故障,會經過 7200+75*9=7875 秒即 2 小時 11 分 15 後,伺服器才會判斷該連接失效,以上參數可以手動設置。
十五、TCP/IP 協議與 Socket 之間是什麼關係?#
網絡有一段關於 Socket 和 TCP/IP 協議關係的說法比較容易理解:
TCP/IP 只是個協議棧,就像操作系統的運行機制一樣,必須要具體實現,同時還要提供對外的操作接口。這個就像操作系統會提供標準的編程接口,比如 Win32 編程接口一樣,TCP/IP 也要提供可供程序員做網絡開發所用的接口,這就是 Socket 編程接口。
所以,Socket 跟 TCP/IP 並沒有必然的聯繫,Socket 編程接口在設計的時候,就希望能適應其他的網絡協議。Socket 的出現只是可以更方便的使用 TCP/IP 協議棧而已,其對 TCP/IP 進行了抽象,形成了一些最基本的函數接口,比如 Send,Listen 等。
十六、什麼是 SYN 攻擊?#
我們都知道 TCP 連接建立是需要三次握手,假設攻擊者短時間偽造不同 IP 地址的 SYN 報文,伺服器每接收到一個 SVN 報文,就進入 SYN_RCVD 狀態,但伺服器發送出去的 ACK + SYN 報文,無法得到未知 IP 主機的 ACK 應答,久而久之就會佔滿伺服器的 SYN 接收隊列(未連接隊列),使得伺服器不能為正常用戶服務。
十七、如何避免 SYN 攻擊?#
避免 SYN 攻擊的兩個方案:
通過修改內核參數,控制隊列大小,並確定好當隊列滿之後應該如何處理,比如隊列滿之後,對新的 SYN 直接回覆 RST,丟棄連接。
當 SYN 隊列滿了之後,後續收到的 SYN,不直接進入 SYN 隊列,而是先計算 Cookie 值,再發送,後續可以驗證 ACK 包的合法性。
十八、TCP 伺服器 Socket 編程流程#
-
伺服器初始化 Socket,得到文件描述符
-
伺服器調用 Bind,將綁定在 IP 地址和端口
-
伺服器調用 Listen,進行監聽
-
伺服器調用 Accept,建立客戶端連接
-
通過 Send 向客戶端發送消息
-
通過 Receive 接收客戶端消息
十九、TCP 客戶端 Socket 編程?#
-
客戶端初始化 Socket,得到文件描述符
-
客戶端調用 Connect,連接伺服器
-
連接成功調用 Send 向客戶端發送消息
-
通過 Receive 接收客戶端消息
二十、Listen 中的 backlog 參數什麼意義?#
Linux 內核中會維護兩個隊列:
未完成連接隊列(SYN 隊列):接收到一個 SYN 建立連接請求,處於 SYN_RCVD 狀態; 已完成連接隊列(Accpet 隊列):已完成 TCP 三次握手過程,處於 ESTABLISHED 狀態;
在內核 2.2 之後,backlog 變成 Accept 隊列,也就是已完成連接建立的隊列長度,所以現在通常認為 backlog 是 Accept 隊列。