1. 計算機網絡分層
OSI模型
- 物理層
- 數據鏈路層
- 網絡層
- 傳輸層
- 會話層
- 表示層
物理層:定義了物理設備的標準,傳輸比特流(二進制數據轉換爲強弱不同的電流,到達目的後再轉換爲機器碼)
數據鏈路層:定義瞭如何格式化數據以及如何傳輸,提供錯誤檢測以及糾正,將比特數據轉換爲幀
網絡層:將網絡地址翻譯爲對應的物理地址,並決定將數據從發送方路由到接收方,選擇最佳路由。IP協議,IP數據包
傳輸層:接受上一層的數據,在必要的時候將數據進行分割。並將這些數據交給網絡層,且保證這些數據段有效的到達接收方。TCP協議,UDP協議
會話層:自動收發包,自動尋址。在不同機器上的用戶之間建立及管理會話,接觸或建立與別的節點的聯繫
表示層:解決不同系統之間通信語法不同的問題,數據加密,代碼轉化、將數據以網絡能理解的方案進行格式化。
應用層:規定接收方和發送方以一個固定長度的消息頭,例如文件傳輸、電子郵件、文件服務、虛擬終端等。HTTP協議
2. TCP/IP協議
TCP:傳輸控制協議
- 面向連接的、可靠的、基於字節流的傳輸層通信協議
- 將應用層的數據流分割成報文段併發送給目標節點的TCP層
- 數據包都有序號,保證到目標節點的按序處理。對方收到則發送ACK確認,如果在合理的往返時延內未收到確認則重傳
- 使用檢驗和來檢驗數據在傳輸過程中是否有誤
TCP報文頭部結構
-
源端口和目的端口: 各佔2個字節,分別寫入源端口號和目的端口號,源端口號在需要對方回信時選用,目的端口在終點交付報文的時必須使用
-
序號:在一個TCP連接中傳送的字節流中的每一個字節都按順序編號
-
確認號:是期望收到對方下一個報文段的第一個數據字節的序號。若確認號 = N,則表明:到序號N-1爲止的所有數據都已正確收到
-
數據偏移: 指出TCP報文段的數據起始處距離TCP報文段的起始處有多遠
-
Flags
- URG:緊急指針標誌,爲1表明緊急指針有效,告訴系統此報文段中有緊急數據,優先級高
- ACK:確認序號標誌,僅當ACK=1時確認號字段纔有效。TCP規定,在連接建立後所有穿梭那個的報文段必須把ACK置爲1
- PSH:push標誌,用於提高優先級
- RST:重置連接標誌,當RST=1時,表明TCP連接中出現嚴重差錯,必須釋放連接並重新建立連接
- SYN:在連接時用來同步序號,當SYN=1而ACK=0時,表明這是一個連接請求的報文段,對方若同意建立連接,則響應的報文端中ACK=1且SYN=1。
- FIN: 用於釋放一個連接,當FIN=1時,表明此報文段數據已發送完畢,並要求釋放連接。
-
窗口: 窗口值作爲接收方讓發送方設置其發送窗口的依據,用於流量控制
-
檢驗和: 檢驗和字段檢驗的範圍包括首部和數據兩部分
-
緊急指針: 僅在URG=1時纔有效,用於指出本報文段中的緊急數據的字節數。
-
可選項: 僅用於使整個TCP報文的首部長度是4的整數倍
TCP的三次握手
- 假設A、B首次建立通信
- 服務端創建傳輸控制塊TCP時刻監聽客戶端發送的請求,服務端進入Listen狀態
- 客戶端創建傳輸控制塊TCP向服務器發送連接請求報文,SYN=1 初始序號爲 x,客戶端進入SYN-SENT(同步已發送)狀態 (第一次握手)
- 服務端收到請求報文後,若同意建立連接,則向A發送確認報文段、在確認報文段中應把ACK 和 SYN都置爲1,確認號ack=x+1(因爲請求報文段中消耗了一個序號)、爲自己的緩存初始化序列號seq=y。服務端進入SYN-RCVD(同步收到)狀態 (第二次握手)
- 客戶端接收到服務端的確認報文後,還要給服務端發送確認報文,確認報文中ACK=1、確認號ack=y+1,自己的序號seq=x+1,這時TCP連接已經建立,客戶端和服務端進入ESTANLISHED(已建立連接)狀態 (第三次握手)
爲什麼需要三次握手才能建立連接
-
爲了初始化seq(序號)的初始值,以保證傳輸的數據不會因爲網絡上的問題而亂序
-
首次握手時的隱患——SYN超時
-
問題起因分析
-
客戶端收到服務端的SYN,回覆的SYN-ACK的時候未收到ACK確認
-
服務端不斷重試直至超時,Linux默認等待63s才能斷開連接
-
針對SYN Flood的防護措施
- SYN隊列滿後,通過tcp_syncookies參數回發SYN Cookie
- 若爲正常連接則服務端會回發SYN-COOKIE,直至完成連接
-
-
建立連接後,客戶端出現故障怎麼辦
- 向對方發送保活探測報文,如果未收到響應則繼續發送
- 嘗試次數打到保活探測數仍未收到響應則中斷連接
-
-
TCP的四次揮手
-
假設數據傳輸過程中,由客戶端進程主動關閉,則服務端被動關閉
-
客戶端進程先向其TCP發送***連接釋放***報文段,並停止再發送數據,連接釋放報文段中將終止控制位FIN置爲1,seq=u(等於已傳送過的數據的最後一個字節的序號加1)客戶端進入FIN–WAIT-1(
終止等待)狀態,等待B確認。FIN報文段即使不攜帶數據,它也消耗一個序號。 (第一次揮手) -
服務端進程收到連接釋放報文段後即發出確認,確認號是ack=u+1,seq爲v(等於客戶端前面已傳送的數據的最後一個字節的序號加1),然後服務端進入CLOSE-WAIT(關閉等待)狀態。TCP服務器此時會通知高層應用進程,因爲從客戶端到服務端這個方向的連接就被釋放了,這是TCP連接處於半關閉狀態,這時客戶端已經沒有數據向服務端發送了,但是服務端要發送數據,客戶端仍要接收。也就是說,從服務端到客戶端這個方向的連接還沒有關閉,這個狀態可能會持續一段時間。(第二次揮手)
-
客戶端收到服務端的確認後,就進入FIN-WAIT-2(終止等待2)狀態,等待服務端發送的連接釋放報文段。
-
若服務端已經沒有向客戶端發送的數據,其應用程序就通知TCP釋放連接,這時服務端發送的連接釋放報文必須時FIN置爲1,假定服務端進程的序號爲w(在半關閉狀態可能又發送了一部分數據)。服務端還必須重複上次已經發送的確認號ack=u+1,這時服務端進程進入LAST-ACK(最後確認)狀態,等待客戶端的確認。 (第三次揮手)
-
客戶端收到服務端發送的連接釋放報文後,必須對此進行確認。在確人報文段中吧ACK置爲1,確認號ack=w+1,而自己的序號seq=u+1,然後進入TIME-WAIT(時間等待)狀態。此時客戶端進程的TCP連接還沒有釋放掉,必須等待時間等待計時器設置的時間2MSL之後,客戶端才能進入CLOSED狀態。RFC793建議爲2min,Linux爲30s,而服務端接收到客戶端的確認報文後,立即進入CLOSED狀態關閉連接。(第四次揮手)
爲什麼會有TIME-WAIT狀態(爲什麼要等待2MSL)
- 確保有足夠的時間讓對方收到ACK包
- 避免新舊連接混淆
爲什麼需要四次揮手才能斷開連接
- 因爲TCP協議是全雙工,發送方和接收方都需要FIN報文和ACK報文
服務器出現大量CLOSE_WAIT狀態的原因
-
客戶端發送了一個連接釋放的報文之後,服務器端沒有發送確認報文,即客戶端關閉了socket連接,但服務端忙於讀或寫,沒有及時的關閉連接。
- 檢查代碼,特別是釋放資源的代碼
- 檢查配置,特別是處理請求的線程配置