基礎#
TCP/IP 網路模型#
-
應用層:負責向用戶提供一組應用程序。
HTTP、FTP、Telnet、DNS、SMTP 等。應用層工作在用戶態。
-
傳輸層:負責端到端的通信。
TCP:流量控制、超時重傳、擁塞控制等。/UDP
MSS(最大分段大小) -> TCP 段(TCP Segment)
-
網路層:負責網路包的封裝、分片、路由、轉發。
IP 協議:尋址、路由。/ICMP
MTU(最大傳輸單元) -> 分片
-
鏈路層:負責網路包在物理網路中的傳輸,比如網路包的封幀、MAC 尋址、差錯檢測,以及通過網卡傳輸網路幀等。/ARP
OSI 七層網路模型#
- 應用層,負責給應用程序提供統一的接口;
- 表示層,負責把數據轉換成兼容另一個系統能識別的格式;
- 會話層,負責建立、管理和終止表示層實體之間的通信會話;
- 傳輸層,負責端到端的數據傳輸;
- 網路層,負責數據的路由、轉發、分片;
- 數據鏈路層,負責數據的封幀和差錯檢測,以及 MAC 尋址;
- 物理層,負責在物理網路中傳輸數據幀;
從 url 到網頁顯示#
- 解析 URL -> web 伺服器和檔名
- 生成 HTTP 請求
- DNS 域名解析
- TCP 三次握手建立連接
- TCP 報文生成
- IP 報文生成 -> IP 地址負責遠程定位
- MAC 報文生成(使用 ARP 查詢 MAC 地址) -> MAC 地址負責兩點傳輸
- 網卡,在開頭添加報頭和起始幀分界符,在末尾添加用於檢測錯誤的幀校驗序列(FCS),數字信息 -> 電信號
- 交換機(二層網路設備),查交換機的 MAC 地址表(MAC - 端口),沒有就轉發到所有端口
- 路由器(三層網路設備),路由表查 IP(路由匹配),ARP 查 MAC。
- 到達伺服器,解析數據包,發送 HTTP 響應
- 客戶端收到 HTTP 響應,渲染頁面
- TCP 四次揮手斷開連接
轉發過程中,源 IP 地址和目標 IP 地址不變,源 MAC 和目標 MAC 發生變化。
總體來說分為以下幾個步驟:
- 在瀏覽器中輸入指定網頁的 URL。
- 瀏覽器通過 DNS 協議,獲取域名對應的 IP 地址。
- 瀏覽器根據 IP 地址和端口號,向目標伺服器發起一個 TCP 連接請求。
- 瀏覽器在 TCP 連接上,向伺服器發送一個 HTTP 請求報文,請求獲取網頁的內容。
- 伺服器收到 HTTP 請求報文後,處理請求,並返回 HTTP 響應報文給瀏覽器。
- 瀏覽器收到 HTTP 響應報文後,解析響應體中的 HTML 代碼,渲染網頁的結構和樣式,同時根據 HTML 中的其他資源的 URL(如圖片、CSS、JS 等),再次發起 HTTP 請求,獲取這些資源的內容,直到網頁完全加載顯示。
- 瀏覽器在不需要和伺服器通信時,可以主動關閉 TCP 連接,或者等待伺服器的關閉請求。
HTTP_面試#
HTTP 是超文本傳輸協議,也就是HyperText Transfer Protocol。
什麼是協議#
協議 (protocol) 定義了在兩個或多個通信實體之間交換的報文的格式和順序,以及報文發送和 / 或接收一條報文或其他事件所採取的動作 。
它使用計算機能夠理解的語言確立了一種計算機之間交流通信的規範(兩個以上的參與者),以及相關的各種控制和錯誤處理方式(行為約定和規範)。
HTTP 的狀態碼#
- 1xx:表示一個提示性響應
- 101 表示將切換協議,常見於 WebSocket 連接;
- 2xx:表示一個成功的響應
- 「200 OK」表示成功
- 「204 No Content」表示響應沒有 body 數據
- 「206 Partial Content」表示只發送了部分內容;
- 3xx:表示一個重定向的響應
- 「301 Moved Permanently」表示永久重定向
- 「302 Found」表示臨時重定向
- 303 表示客戶端應該按指定路徑重新發送請求
- 「304 Not Modified」表示資源未修改,重定向至緩存(緩存重定向);
- 4xx:表示一個因為客戶端問題導致的錯誤響應
- 「400 Bad Request」表示客戶端請求的報文有錯誤
- 「403 Forbidden」表示伺服器禁止訪問資源
- 「404 Not Found」表示指定的路徑不存在;
- 5xx:表示一個因為伺服器問題導致的錯誤響應:
- 「500 Internal Server Error」表示伺服器內部故障
- 「501 Not Implemented」表示客戶端請求的功能還不支持
- 「502 Bad Gateway」表示伺服器自身工作正常,訪問後端伺服器發生了錯誤
- 「503 Service Unavailable」表示伺服器很忙暫時無法響應。
HTTP 的常見字段#
HTTP 請求的格式是固定的,它由 HTTP Header 和 HTTP Body 兩部分構成。第一行總是請求方法 路徑 HTTP版本
,例如,GET / HTTP/1.1
表示使用GET
請求,路徑是/
,版本是HTTP/1.1
。
後續的每一行都是固定的Header: Value
格式,我們稱為 HTTP Header,伺服器依靠某些特定的 Header 來識別客戶端請求,例如:
- Host:表示請求的域名,因為一台伺服器上可能有多個網站,因此有必要依靠 Host 來識別請求是發給哪個網站的;
- User-Agent:表示客戶端自身標識信息,不同的瀏覽器有不同的標識,伺服器依靠 User-Agent 判斷客戶端類型是 IE 還是 Chrome,是 Firefox 還是一個 Python 爬蟲;
- Accept:表示客戶端能處理的 HTTP 響應格式,
*/*
表示任意格式,text/*
表示任意文本,image/png
表示 PNG 格式的圖片; - Accept-Language:表示客戶端接收的語言,多種語言按優先級排序,伺服器依靠該字段給用戶返回特定語言的網頁版本。
如果是GET
請求,那麼該 HTTP 請求只有 HTTP Header,沒有 HTTP Body。如果是POST
請求,那麼該 HTTP 請求帶有 Body,以一個空行分隔。
POST
請求通常要設置Content-Type表示 Body 的類型,Content-Length表示 Body 的長度,這樣伺服器就可以根據請求的 Header 和 Body 做出正確的響應。
HTTP 響應也是由 Header 和 Body 兩部分組成。響應的第一行總是HTTP版本 響應代碼 響應說明
,例如,HTTP/1.1 200 OK
表示版本是HTTP/1.1
,響應代碼是200
,響應說明是OK
。客戶端只依賴響應代碼判斷 HTTP 響應是否成功。HTTP 有固定的響應代碼。
HTTP 協議通過設置回車符、換行符作為 HTTP header 的邊界,通過 Content-Length 字段作為 HTTP body 的邊界,這兩個方式都是為了解決 “粘包” 的問題
其他字段:
- Connection:最常用於客戶端要求伺服器使用「HTTP 長連接」機制,以便其他請求復用。
- Content-Encoding:說明數據的壓縮方法。表示伺服器返回的數據使用了什麼壓縮格式。
GET 與 POST#
GET 的語義是從伺服器獲取指定的資源。GET 請求的參數位置一般是寫在 URL 中,URL 規定只能支持 ASCII,所以 GET 請求的參數只允許 ASCII 字符,而且瀏覽器會對 URL 的長度有限制(HTTP 協議本身對 URL 長度並沒有做任何規定)。
POST 的語義是根據請求負荷(報文 body)對指定的資源做出處理。POST 請求攜帶數據的位置一般是寫在報文 body 中,body 中的數據可以是任意格式的數據,只要客戶端與伺服端協商好即可,而且瀏覽器不會對 body 大小做限制。
- 在 HTTP 協議裡,所謂的「安全」是指請求方法不會「破壞」伺服器上的資源。
- 所謂的「幂等」,意思是多次執行相同的操作,結果都是「相同」的。
所以GET 方法安全且幂等,因為它是「只讀」操作,可被緩存;POST 方法不安全也不幂等,因為它會修改伺服器上的資源,大都不可緩存。
HTTP 緩存#
強制緩存:只要瀏覽器判斷緩存沒有過期,則直接使用瀏覽器的本地緩存,決定是否使用緩存的主動性在於瀏覽器這邊。
Cache-Control
,是一個相對時間;Expires
,是一個絕對時間;
協商緩存:與伺服端協商之後,通過協商結果來判斷是否使用本地緩存。HTTP 200 OK/ HTTP 304
- 基於唯一標識實現:響應頭部中
Etag
(唯一標識響應資源)和請求頭部中的If-None-Match
; - 基於時間實現:響應頭部中的
Last-Modified
和請求頭部中的If-Modified-Since
;
注意,協商緩存這兩個字段都需要配合強制緩存中 Cache-Control 字段來使用,只有在未能命中強制緩存的時候,才能發起帶有協商緩存字段的請求。
HTTP 特性(HTTP/1.1)#
HTTP 優缺點#
HTTP 的優點是「簡單、靈活和易於擴展、應用廣泛和跨平台」。
HTTP 的缺點是「無狀態、明文傳輸」,(明文傳輸 + 無法驗證報文完整性) -> 「不安全」
HTTP 性能#
HTTP 協議是基於 TCP/IP,並且使用了「請求 - 應答」的通信模式:
- 長連接:只要任意一端沒有明確提出斷開連接,則保持 TCP 連接狀態,減少了 TCP 連接的重複建立和斷開所造成的額外開銷,減輕了伺服器端的負載。
- 管道(pipeline)網路傳輸:同一個 TCP 連接,客戶端發送請求後,不必等待收到響應,就可以發送下一個請求,減少整體的響應時間。但是伺服器必須按照接收請求的順序發送對這些管道化請求的響應。
- 隊頭阻塞:如果伺服器在處理 A 請求時耗時比較長,那麼後續的請求的處理都會被阻塞住,這稱為「隊頭堵塞」。HTTP/1.1 管道解決了請求的隊頭阻塞,但是沒有解決響應的隊頭阻塞。
HTTP/1.1 的性能一般,後續的 HTTP/2 和 HTTP/3 就是在優化 HTTP 的性能。
HTTP 與 HTTPS#
- 建立連接時候:https 比 http 多了 TLS 的握手過程;
- 傳輸內容的時候:https 會把數據進行加密,通常是對稱加密數據;
HTTP 與 HTTPS 的區別#
- 安全
- 建立連接
- 預設端口
- URL 前綴
- 證書
HTTPS 解決的 HTTP 的安全問題#
HTTPS 在 HTTP 與 TCP 層之間加入了 SSL/TLS
協議
-
竊聽風險 -> 信息加密 -> 混合加密
-
篡改風險 -> 校驗機制 -> 摘要算法
+ 數字簽名- 可以通過哈希算法來保證消息的完整性;
可以通過數字簽名來保證消息的來源可靠性(能確認消息是由持有私鑰的一方發送的);
-
冒充風險 -> 身份證書 -> 把伺服器公鑰放到數字證書中
CA 對數字證書進行一個簽名,確保該證書是可信的。(證書信任鏈問題)
本質:客戶端信任伺服端的問題
HTTPS 建立連接#
SSL/TLS 協議基本流程:
- 客戶端向伺服器索要並驗證伺服器的公鑰。
- 雙方協商生成「會話秘鑰」。
- 雙方採用「會話秘鑰」進行加密通信。
前兩步就是 SSL/TLS 的建立過程,也就是 TLS 握手階段,涉及四次通信(SSL/TLS 1.2)。
使用不同的密鑰交換算法,TLS 握手流程也不一樣,現在常用的密鑰交換算法有兩種:RSA 算法 和 ECDHE 算法。
-
ClientHello
,由客戶端向伺服器發起加密通信請求客戶端隨機數(Client Random) ...
-
SeverHello
,伺服器收到客戶端請求後,向客戶端發出響應伺服器端隨機數(Server Random) + 伺服器的數字證書 ...
-
客戶端回應
公鑰加密隨機數 pre-master key + 客戶端握手結束通知 ...
-
伺服器的最後回應
伺服器握手結束通知 + 握手摘要
至此,整個 TLS 的握手階段結束,客戶端與伺服器進入加密通信,就完全是使用普通的 HTTP 協議,只不過用「會話秘鑰」加密內容。
HTTPS 保證數據完整性#
TLS 在實現上分為握手協議和記錄協議兩層:
- TLS 握手協議即 TLS 四次握手的過程,負責協商加密算法和生成對稱密鑰;
- TLS 記錄協議負責保護應用程序數據並驗證其完整性和來源,使用記錄協議對 HTTP 數據加密;
TLS 記錄協議主要負責消息(HTTP 數據)的壓縮,加密及數據的認證:
- 將消息分割為多個較短的片段,然後分別對這些片段進行壓縮
- 為經過壓縮的片段加上消息認證碼(MAC,通過哈希算法得到),這是為了保證數據完整性並進行數據的認證。
- 使用對稱密鑰對 壓縮後的消息片段 + 消息認證碼 進行加密
- 加密後的數據再加上數據類型、版本號、壓縮後的長度組成的報頭就是最終的報文數據。
記錄協議完成後,最終的報文數據將傳遞到傳輸控制協議 (TCP) 層進行傳輸。
HTTP 的演變#
HTTP/1.1 Vs. HTTP/1.0#
- 長連接
- 支持管道(pipeline)網路傳輸,不必等響應就可發出接下來的請求
HTTP/2.0 Vs. HTTP/1.1#
- HTTP/2.0 基於 HTTPS,安全性高
- 頭部壓縮,HPACK 算法
- 二進制格式
- 並發傳輸,Stream,多個請求復用一個 TCP 連接
- 伺服器推送
HTTP/2.0 依然存在隊頭阻塞問題,發生在 TCP 層,只有 TCP 數據是連續的,應用層才能從內核中讀取到數據,一旦發生丟包,就會阻塞住所有的 HTTP 請求
HTTP/3#
HTTP/3 下層使用 UDP 協議以解決隊頭阻塞問題。
基於 UDP 的 QUIC 協議可以實現類似 TCP 的可靠性傳輸,QUIC 協議有以下特點:
- 無隊頭阻塞:當某個流發生丟包時,只會阻塞這個流,不會影響其他流,多個 Stream 之間沒有依賴,相互獨立。
- 更快的連接建立:QUIC 內部包含了 TLS,僅需 1 個 RTT 就可以「同時」完成建立連接與密鑰協商。
- 連接遷移:QUIC 協議沒有用四元組的方式來 “綁定” 連接,而是通過連接 ID 來標記通信的兩個端點。
- 安全性:在 HTTP/2.0 中,TLS 用於加密和認證整個 HTTP 會話,包括所有的 HTTP 頭部和數據負載。TLS 的工作是在 TCP 層之上,它加密的是在 TCP 連接中傳輸的應用層的數據,並不會對 TCP 頭部以及 TLS 記錄層頭部進行加密,所以在傳輸的過程中 TCP 頭部可能會被攻擊者篡改來干擾通信。而 HTTP/3.0 的 QUIC 對整個數據包(包括報文頭和報文體)進行了加密與認證處理,保障安全性。
所以,QUIC 是一個在 UDP 之上的伪 TCP + TLS + HTTP/2 的多路復用的協議。
TCP_面試#
TCP 頭格式#
TCP 頭部在不使用選項的話占用 20 個字節:
- 源端口號 (16 位) + 目標端口號 (16 位)
- 序列號 (32 位):解決亂序問題
- 確認應答號 (32 位):解決丟包問題
- 首部長度 (4 位) + 保留 (6 位) + 控制位 (6 位) + 窗口大小 (16 位)
- 校驗和 (16 位) + 緊急指針 (16 位)
TCP 的存在意義#
網路層的 IP 協議不保證可靠交付,如果需要保障網路數據包的可靠性,必須交由上層 (傳輸層) 的 TCP 協議來負責。
因為 TCP 協議是一個工作在傳輸層的可靠數據傳輸的服務,能確保收到的網路數據包是無損壞的、無間隔的、無冗餘的、按序的。
什麼是 TCP#
TCP 是一個面向連接的、可靠的、基於字節流的傳輸層通信協議。
什麼是 TCP 連接#
連接:用於保證可靠性和流量控制維護的某些狀態信息的組合,包括 socket、序列號、窗口大小。
建立 TCP 連接需要客戶端與伺服端達成以下信息的共識:
- socket:TCP 四元組
- 序列號:用於解決亂序問題
- 窗口大小:用於流量控制
TCP 與 UDP 的區別#
UDP 頭部,固定為 8 個字節:
- 源端口號 (16 位) + 目的端口號 (16 位)
- 包長度 (16 位) + 校驗和 (16 位)
UDP 只使用 IP 提供的面向無連接的通信服務。
TCP 與 UDP 的區別在於以下幾點 (把握邏輯來記憶):
- 連接:TCP 是面向連接的,UDP 是面向無連接的
- 服務對象:TCP 是端到端的兩點服務,UDP 可以一對多
- 可靠性:TCP 是可靠交付數據的,UDP 是盡最大努力交付,不保證可靠交付
- TCP 提供擁塞控制和流量控制機制,保證數據傳輸的安全性,UDP 沒有
- 首部開銷:TCP 不使用選項的情況首部為 20 個字節,UDP 首部固定為 8 個字節
- 傳輸方式:TCP 是基於字節流的流式傳輸,UDP 是以包為單位發送的,有邊界
- 分片:TCP 數據大小如果大於 MSS 會在傳輸層進行分片,UDP 則只使用網路層 IP 協議的分片 (大於 MTU)
TCP 的應用場景:
- FTP 文件傳輸
- HTTP/HTTPS
UDP 的應用場景:
- 多媒體通信
- 廣播通信
- 包總量較小的通信:如 DNS、SNMP 等
TCP 連接建立#
TCP 建立連接是通過三次握手進行的。
為什麼是三次握手,而不是兩次、四次?#
-
阻止重複歷史連接的初始化
「舊 SYN 報文」稱為歷史連接,TCP 使用三次握手建立連接的最主要原因就是防止「歷史連接」初始化了連接。
-
同步雙方的初始序列號
客戶端發送攜帶「初始序列號」的
SYN
報文的時候,需要伺服端回一個ACK
應答報文,表示客戶端的 SYN 報文已被伺服端成功接收,那當伺服端發送「初始序列號」給客戶端的時候,依然也要得到客戶端的應答回應,這樣一來一回,才能確保雙方的初始序列號能被可靠的同步。 -
避免資源浪費
如果只有「兩次握手」,客戶端發送的
SYN
報文在網路中阻塞了,重複發送多次SYN
報文,那麼伺服端在收到請求後就會建立多個冗餘的無效連接,造成不必要的資源浪費。
為什麼建立 TCP 連接時要求初始化的序列號不一樣?#
- 防止歷史報文被相同四元組的連接錯誤地接收 (主要方面)
- 防止黑客偽造相同序列號的 TCP 報文
初始化序列號 ISN 隨機生成算法:ISN = M + F (localhost, localport, remotehost, remoteport)。
M
是一個計時器,這個計時器每隔 4 微秒加 1。F
是一個 Hash 算法,根據源 IP、目的 IP、源端口、目的端口生成一個隨機數值。要保證 Hash 算法不能被外部輕易推算得出,用 MD5 算法是一個比較好的選擇。
隨機數是會基於時鐘計時器遞增的,基本不可能會隨機成一樣的初始化序列號。
關於 SYN 攻擊#
假設攻擊者短時間偽造不同 IP 地址的 SYN
報文,伺服端每接收到一個 SYN
報文,就進入SYN_RCVD
狀態,但伺服端發送出去的 ACK + SYN
報文,無法得到未知 IP 主機的 ACK
應答,久而久之就會佔滿伺服端的半連接隊列,使得伺服端不能為正常用戶服務。
SYN 攻擊方式最直接的表現就會把 TCP 半連接隊列打滿,這樣當 TCP 半連接隊列滿了,後續再在收到 SYN 報文就會丟棄,導致客戶端無法和伺服端建立連接。
避免 SYN 攻擊方式,可以有以下四種方法:
- 調大 netdev_max_backlog;
- 增大 TCP 半連接隊列;
- 開啟 tcp_syncookies;
- 減少 SYN+ACK 重傳次數
TCP 連接斷開#
TCP 斷開連接是通過四次揮手進行的,每個方向都需要一個 FIN 和一個 ACK。
關於 TIME_WAIT 狀態#
需要 TIME-WAIT 狀態,主要是兩個原因:
-
防止歷史連接中的數據,被後面相同四元組的連接錯誤的接收;
TIME_WAIT 狀態,狀態會持續
2MSL
時長,這個時間足以讓兩個方向上的數據包都被丟棄,使得原來連接的數據包在網路中都自然消失,再出現的數據包一定都是新建立連接所產生的。(MSL
是 Maximum Segment Lifetime,報文最大生存時間。) -
保證「被動關閉連接」的一方,能被正確的關閉;
TIME-WAIT 作用是等待足夠的時間以確保最後的 ACK 能讓被動關閉方接收,從而幫助其正常關閉。
假設客戶端沒有 TIME_WAIT 狀態,而是在發完最後一次回 ACK 報文就直接進入 CLOSE 狀態,如果該 ACK 報文丟失了,伺服端則重傳的 FIN 報文,而這時客戶端已經進入到關閉狀態了,在收到伺服端重傳的 FIN 報文時,就會回 RST 報文。
為了防止這種情況出現,客戶端必須等待足夠長的時間,確保伺服端能夠收到 ACK,如果伺服端沒有收到 ACK,那麼就會觸發 TCP 重傳機制,伺服端會重新發送一個 FIN,這樣一去一來剛好兩個 MSL 的時間。
客戶端在收到伺服端重傳的 FIN 報文時,TIME_WAIT 狀態的等待時間,會重置回 2MSL。
過多的 TIME-WAIT 狀態主要的危害有兩種:
- 第一是佔用系統資源,比如文件描述符、內存資源、CPU 資源、線程資源等;
- 第二是佔用端口資源,端口資源也是有限的,一般可以開啟的端口為
32768~61000
,也可以通過net.ipv4.ip_local_port_range
參數指定範圍。
TIME_WAIT 是我們的朋友,它是有助於我們的,不要試圖避免這個狀態,而是應該弄清楚它。
如果伺服端要避免過多的 TIME_WAIT 狀態的連接,就永遠不要主動斷開連接,讓客戶端去斷開,由分佈在各處的客戶端去承受 TIME_WAIT。
如果伺服器出現大量的 TIME_WAIT 狀態的 TCP 連接,就是說明伺服器主動斷開了很多 TCP 連接,有以下幾種場景:
- 第一個場景:HTTP 沒有使用長連接 (Keep-Alive)
- 第二個場景:HTTP 長連接超時
- 第三個場景:HTTP 長連接的請求數量達到上限
TCP 的保活機制#
定義一個時間段,在這個時間段內,如果沒有任何連接相關的活動,TCP 保活機制會開始作用,每隔一個時間間隔,發送一個探測報文,該探測報文包含的數據非常少,如果連續幾個探測報文都沒有得到響應,則認為當前的 TCP 連接已經死亡,系統內核將錯誤信息通知給上層應用程序。
TCP 保活的這個機制檢測的時間是有點長,我們可以自己在應用層實現一個心跳機制。
Socket 編程#
針對 TCP 進行 Socket 編程:
- 伺服端和客戶端初始化
socket
,得到文件描述符; - 伺服端調用
bind
,將 socket 綁定在指定的 IP 地址和端口; - 伺服端調用
listen
,進行監聽; - 伺服端調用
accept
,等待客戶端連接; - 客戶端調用
connect
,向伺服端的地址和端口發起連接請求; - 伺服端
accept
返回用於傳輸的socket
的文件描述符; - 客戶端調用
write
寫入數據;伺服端調用read
讀取數據; - 客戶端斷開連接時,會調用
close
,那麼伺服端read
讀取數據的時候,就會讀取到EOF
,待處理完數據後,伺服端調用close
,表示連接關閉。
伺服端調用 accept
時,連接成功了會返回一個已完成連接的 socket,後續用來傳輸數據。監聽的 socket 和真正用來傳送數據的 socket,是「兩個」socket,一個叫作監聽 socket,一個叫作已完成連接 socket。
成功連接建立之後,雙方開始通過 read 和 write 函數來讀寫數據,就像往一個文件流裡面寫東西一樣。
IP_基礎#
IP 負責在「沒有直連」的兩個網路之間進行通信傳輸;
MAC 的作用是實現「直連」的兩個設備之間通信;
IP 地址分類#
分類地址: A 類、B 類、C 類、D 類、E 類。
無分類地址 CIDR:32 比特的 IP 地址被劃分為兩部分,前面是網路號,後面是主機號。
無類別域間路由(英語:Classless Inter-Domain Routing,簡稱CIDR)
子網掩碼,掩碼的意思就是掩蓋掉主機號,剩餘的就是網路號。將子網掩碼和 IP 地址按位計算 AND,就可得到網路號。
可以通過子網掩碼劃分出網路號和主機號,那實際上子網掩碼還有一個作用,那就是劃分子網。
子網劃分實際上是將主機地址分為兩部分:子網網路地址和子網主機地址。
IP 地址與路由控制#
IP 地址的網路地址這一部分是用於進行路由控制。
路由控制表中記錄著網路地址與下一步應該發送至路由器的地址。在主機和路由器上都會有各自的路由器控制表。
在發送 IP 包時,首先要確定 IP 包首部中的目標地址,再從路由控制表中找到與該地址具有相同網路地址的記錄,根據該記錄將 IP 包轉發給相應的下一個路由器。如果路由控制表中存在多條相同網路地址的記錄,就選擇相同位數最多的網路地址,也就是最長匹配。
環回地址是在同一台計算機上的程序之間進行網路通信時所使用的一個默認地址。
計算機使用一個特殊的 IP 地址 127.0.0.1 作為環回地址。與該地址具有相同意義的是一個叫做 localhost
的主機名。使用這個 IP 或主機名時,數據包不會流向網路。
IP 分片與重組#
每種數據鏈路的最大傳輸單元 MTU
都是不相同的,如 FDDI 數據鏈路 MTU 4352、以太網的 MTU 是 1500 字節等。
每種數據鏈路的 MTU 之所以不同,是因為每個不同類型的數據鏈路的使用目的不同。使用目的不同,可承載的 MTU 也就不同。
當 IP 數據包大小大於 MTU 時,IP 數據包就會被分片。
經過分片之後的 IP 數據報在被重組的時候,只能由目標主機進行,路由器是無法進行重組的。
在分片傳輸中,一旦某個分片丟失,則會造成整個 IP 數據報作廢,所以 TCP 引入了 MSS
也就是在 TCP 層進行分片不由 IP 層分片,那麼對於 UDP 我們儘量不要發送一個大於 MTU
的數據報文。
IPv6 基本認識#
IPv4 地址長度共 32 位 (4 個字節),是以每 8 位作為一組,並用點分十進制的表示方式。
IPv6 地址長度是 128 位 (16 個字節),是以每 16 位作為一組,每組用冒號「:」隔開。
如果出現連續的 0 時還可以將這些 0 省略,並用兩個冒號「::」隔開。但是,一個 IP 地址中只允許出現一次兩個連續的冒號。
IPv6 不僅僅只是可分配的地址變多了,它還有非常多的亮點。
- IPv6 可自動配置,即使沒有 DHCP 伺服器也可以實現自動分配 IP 地址,便捷到即插即用。
- IPv6 包頭包首部長度採用固定的值
40
字節,去掉了包頭校驗和,簡化了首部結構,減輕了路由器負荷,大大提高了傳輸的性能。 - IPv6 有應對偽造 IP 地址的網路安全功能以及防止線路竊聽的功能,大大提升了安全性。
- ...
IPv6 相比 IPv4 的首部改進:
- 取消了首部校驗和字段。 因為在數據鏈路層和傳輸層都會校驗,因此 IPv6 直接取消了 IP 的校驗。
- 取消了分片 / 重新組裝相關字段。 分片與重組是耗時的過程,IPv6 不允許在中間路由器進行分片與重組,這種操作只能在源與目標主機,這將大大提高了路由器轉發的速度。
- 取消選項字段。 選項字段不再是標準 IP 首部的一部分了,但它並沒有消失,而是可能出現在 IPv6 首部中的「下個首部」指出的位置上。刪除該選項字段使的 IPv6 的首部成為固定長度的
40
字節。
IP 協議相關技術#
DNS 域名解析#
DNS 可以將域名網址自動轉換為具體的 IP 地址
域名的層級關係類似一個樹狀結構:
- 根 DNS 伺服器
- 頂級域 DNS 伺服器(com)
- 權威 DNS 伺服器(server.com)
瀏覽器首先看一下自己的緩存裡有沒有,如果沒有就向操作系統的緩存要,還沒有就檢查本機域名解析文件 hosts
,如果還是沒有,就會 DNS 伺服器進行查詢,查詢的過程如下:
- 客戶端首先會發出一個 DNS 請求,問 www.server.com 的 IP 是啥,並發給本地 DNS 伺服器(也就是客戶端的 TCP/IP 設置中填寫的 DNS 伺服器地址)。
- 本地域名伺服器收到客戶端的請求後,如果緩存裡的表格能找到 www.server.com 則,它直接返回 IP 地址。如果沒有,本地 DNS 會去問它的根域名伺服器:“老大,能告訴我 www.server.com 的 IP 地址嗎?” 根域名伺服器是最高層次的,它不直接用於域名解析,但能指明一條道路。
- 根 DNS 收到來自本地 DNS 的請求後,發現後置是 .com,說:“www.server.com 這個域名歸 .com 區域管理”,我給你 .com 頂級域名伺服器地址給你,你去問問它吧。”
- 本地 DNS 收到頂級域名伺服器的地址後,發起請求問 “老二,你能告訴我 www.server.com 的 IP 地址嗎?”
- 頂級域名伺服器說:“我給你負責 www.server.com 區域的權威 DNS 伺服器的地址,你去問它應該能問到”。
- 本地 DNS 於是轉向問權威 DNS 伺服器:“老三,www.server.com 對應的 IP 是啥呀?”server.com 的權威 DNS 伺服器,它是域名解析結果的原出处。為啥叫權威呢?就是我的域名我做主。
- 權威 DNS 伺服器查詢後將對應的 IP 地址 X.X.X.X 告訴本地 DNS。
- 本地 DNS 再將 IP 地址返回客戶端,客戶端和目標建立連接。
DNS 域名解析的過程就和我們日常生活中找人問路的過程類似,只指路不帶路。
ARP 地址解析協議#
ARP 是一個通過解析網路層地址來尋找數據鏈路層地址的網路傳輸協議。
ARP 是借助 ARP 請求與 ARP 響應兩種類型的包確定 MAC 地址的。
- 主機會通過廣播發送 ARP 請求,這個包中包含了想要知道的 MAC 地址的主機 IP 地址。
- 當同個鏈路中的所有設備收到 ARP 請求時,會去拆開 ARP 請求包裡的內容,如果 ARP 請求包中的目標 IP 地址與自己的 IP 地址一致,那麼這個設備就將自己的 MAC 地址塞入 ARP 響應包返回給主機。
操作系統通常會把第一次通過 ARP 獲取的 MAC 地址緩存起來,以便下次直接從緩存中找到對應 IP 地址的 MAC 地址。
ARP 協議是已知 IP 地址求 MAC 地址,那 RARP 協議正好相反,它是已知 MAC 地址求 IP 地址。
另外,當發送主機和目的主機不在同一個局域網中時,即便知道對方的 MAC 地址,兩者也不能直接通信,必須經過路由器進行 IP 層的轉發才可以,因為路由器把這個局域網進行了鏈路層上的隔離 (除非進行網路層次的顯示轉發,否則路由器不會把一個局域網中的以太網幀自動的轉發到另一個局域網或者外網中去,如果可以自動轉發,可以想象有多可怕,無效的廣播幀可能像洪水一樣淹沒整個網路,使得網路癱瘓,這也就是路由器的基本功能之一,隔離網路),所以此時,發送主機會把一個網關 IP 地址作為目的 IP 地址 (這是 IP 層決定的),那麼通過 ARP 協議獲得的將不是目的主機的真實 MAC 地址,而是一台可以通往局域網外的路由器的 MAC 地址。於是此後發送主機發往目的主機的所有幀,都將發往該路由器,通過它向外發送。這種情況稱為委託 ARP 或ARP 代理(ARP Proxy)。
DHCP 動態主機設置協議#
DHCP 是一種使網路管理員能夠集中管理和自動分配 IP 網路地址的通信協議。
DHCP 客戶端進程監聽的是 68 端口號,DHCP 服務端進程監聽的是 67 端口號。
- 客戶端首先發起 DHCP 發現報文(DHCP DISCOVER) 的 IP 數據報,由於客戶端沒有 IP 地址,也不知道 DHCP 伺服器的地址,所以使用的是 UDP 廣播通信,其使用的廣播目的地址是 255.255.255.255(端口 67)並且使用 0.0.0.0(端口 68)作為源 IP 地址。DHCP 客戶端將該 IP 數據報傳遞給鏈路層,鏈路層然後將幀廣播到所有的網路中設備。
- DHCP 伺服器收到 DHCP 發現報文時,用 DHCP 提供報文(DHCP OFFER) 向客戶端做出響應。該報文仍然使用 IP 廣播地址 255.255.255.255,該報文信息攜帶伺服器提供可租約的 IP 地址、子網掩碼、默認網關、DNS 伺服器以及 IP 地址租用期。
- 客戶端收到一個或多個伺服器的 DHCP 提供報文後,從中選擇一個伺服器,並向選中的伺服器發送 DHCP 請求報文(DHCP REQUEST進行響應,回顯配置的參數。
- 最後,服務端用 DHCP ACK 報文對 DHCP 請求報文進行響應,應答所要求的參數。
一旦客戶端收到 DHCP ACK 後,交互便完成了,並且客戶端能夠在租用期內使用 DHCP 伺服器分配的 IP 地址。
如果租約的 DHCP IP 地址快過期了,客戶端會向伺服器發送 DHCP 請求報文:
- 伺服器如果同意繼續租用,則用 DHCP ACK 報文進行應答,客戶端就會延長租期。
- 伺服器如果不同意繼續租用,則用 DHCP NACK 報文,客戶端就要停止使用租約的 IP 地址。
可以發現,DHCP 交互中,全程都是使用 UDP 廣播通信。
有了 DHCP 中繼代理以後,對不同網段的 IP 地址分配也可以由一個 DHCP 伺服器統一進行管理。
- DHCP 客戶端會向 DHCP 中繼代理發送 DHCP 請求包,而 DHCP 中繼代理在收到這個廣播包以後,再以單播的形式發給 DHCP 伺服器。
- 伺服器端收到該包以後再向 DHCP 中繼代理返回應答,並由 DHCP 中繼代理將此包廣播給 DHCP 客戶端。
因此,DHCP 伺服器即使不在同一個鏈路上也可以實現統一分配和管理 IP 地址。
NAT 網路地址轉換#
網路地址轉換(英語:Network Address Translation,縮寫:NAT),又稱 IP 動態偽裝(英語:IP Masquerade),是一種在 IP 數據包通過路由器或防火牆時重寫來源或目的 IP 地址或端口的技術。 這種技術普遍應用於有多台主機,但只通過一個公有 IP 地址訪問互聯網的私有網路中。
簡單的來說 NAT 就是同個公司、家庭、教室內的主機對外部通信時,把私有 IP 地址轉換成公有 IP 地址。
可以把 IP 地址 + 端口號一起進行轉換。這樣,就用一個全球 IP 地址就可以了,這種轉換技術就叫網路地址與端口轉換 NAPT。
NAPT 路由器的轉換表,可以正確地轉換地址跟端口的組合。
由於 NAT/NAPT 都依賴於自己的轉換表,因此會有以下的問題:
- 外部無法主動與 NAT 內部伺服器建立連接,因為 NAPT 轉換表沒有轉換記錄。
- 轉換表的生成與轉換操作都會產生性能開銷。
- 通信過程中,如果 NAT 路由器重啟了,所有的 TCP 連接都將被重置。
解決的方法主要有兩種方法。
-
第一種就是改用 IPv6
-
NAT 穿透技術
在 NAT 穿透技術中,NAT 設備後的應用程序處於主動地位,它已經明確地知道 NAT 設備要修改它外發的數據包,因此它主動配合 NAT 設備的操作,主動地建立好映射,這樣就不像以前由 NAT 設備來建立映射了。
客戶端主動從 NAT 設備獲取公有 IP 地址,然後自己建立端口映射條目,然後用這個條目對外通信,就不需要 NAT 設備來進行轉換了。
ICMP#
ICMP 全稱是 Internet Control Message Protocol,也就是互聯網控制報文協議。
ICMP
主要的功能包括:確認 IP 包是否成功送達目標地址、報告發送過程中 IP 包被廢棄的原因和改善網路設置等。
ICMP 大致可以分為兩大類:
- 一類是用於診斷的查詢消息,也就是「查詢報文類型」
- 另一類是通知出錯原因的錯誤消息,也就是「差錯報文類型」
IGMP#
IGMP 是因特網組管理協議,工作在主機(組播成員)和最後一跳路由之間。
- IGMP 報文向路由器申請加入和退出組播組,默認情況下路由器是不會轉發組播包到連接中的主機,除非主機通過 IGMP 加入到組播組,主機申請加入到組播組時,路由器就會記錄 IGMP 路由器表,路由器後續就會轉發組播包到對應的主機了。
- IGMP 報文採用 IP 封裝,IP 頭部的協議號為 2,而且 TTL 字段值通常為 1,因為 IGMP 是工作在主機與連接的路由器之間。
組播地址不是用於機器 ip 地址的,因為組播地址沒有網路號和主機號,所以跟 dhcp 沒關係。組播地址一般是用於 udp 協議,機器發送 UDP 組播數據時,目標地址填的是組播地址,那麼在組播組內的機器都能收到數據包。
是否加入組播組和離開組播組,是由 socket 一個接口實現的,主機 ip 是不用改變的。
其他#
- OSPF(Open Shortest Path First,開放式最短路徑優先):一種內部網關協議(Interior Gateway Protocol,IGP),也是廣泛使用的一種動態路由協議,基於鏈路狀態算法,考慮了鏈路的帶寬、延遲等因素來選擇最佳路徑。
- RIP (Routing Information Protocol,路由信息協議):一種內部網關協議(Interior Gateway Protocol,IGP),也是一種動態路由協議,基於距離向量算法,使用固定的跳數作為度量標準,選擇跳數最少的路徑作為最佳路徑。
- BGP(Border Gateway Protocol,邊界網關協議):一種用來在路由選擇域之間交換網路層可達性信息(Network Layer Reachability Information,NLRI)的路由選擇協議,具有高度的靈活性和可擴展性。