網路、HTTP相關學習總結

CCat發表於2019-03-22

圖解HTTP目錄

引言:上圖是《圖解 HTTP》這本書的目錄,最近又重新讀了一下這本書,然後打算寫篇總結,來加深自己的理解,然而在做總結的時候覺得還是全面總結下網路相關的知識吧,所以又在網上找了大量的資料,最終完成了本文。

鄭重宣告:本文只是我的學習總結,不敢誤人子弟,如果你看到了這篇文章,覺得有什麼錯誤的地方還請指出。本文參考了大量的部落格、文章等,如有侵權,請與我聯絡。謝謝

OSI vs TCP/IP

OSI

OSI全稱為開放式系統互聯通訊參考模型(Open System Interconnection Reference Model)。OSI 將計算機網路體系結構劃分為 7 層。

  1. 物理層:在區域性區域網上傳送資料楨,它負責管理計算機管理通訊裝置和網路媒體之間的互通。包括了針腳、電壓、線纜電壓、集線器、中繼器、網路卡、主機介面等。
  2. 資料鏈路層:負責網路定址、錯誤偵測和改錯。當表頭和表尾被加之資料包時會形成楨。資料連結串列頭(DLH)是包含了實體地址和錯誤偵測和改錯的方法。資料連結串列尾(DLT)是一串指示資料包末端的字串。例如乙太網、無線區域網(Wi-Fi)和通用分組無線服務(GPRS)。
  3. 網路層:決定資料的路徑選擇和轉寄,將網路表頭(NH)加至資料包,以形成分組。網路表頭包含了網路資料,例如:網際網路協議(IP)等。
  4. 傳輸層:把傳輸表頭(TH)加至資料以形成資料包。傳輸表頭包含了所使用的協議等傳送資訊,例如:傳輸控制協議(TCP)等。
  5. 會話層:負責在資料傳輸中設定和維護計算機網路中兩臺計算機之間的通訊連線。
  6. 表示層:將資料轉化為能與接收者的系統格式相容並適合傳輸的格式。
  7. 應用層:提供為應用軟體而設的介面,以設定與另一軟體之間的通訊。例如:HTTP、HTTPS、FTP、TELNET、POP3、SMTP、SSH等。

OSI 模型是一個標準而非實現,TCP/IP 四層模型由 OSI 7 層模型簡化而來,是一個應用的具體實現。

網路、HTTP相關學習總結

下面具體說下四層模型,從下往上說起:

TCP/IP

鏈路層

又名資料鏈路層,網路介面層。用來處理網路連線的硬體部分。

  • 乙太網協議

乙太網(Ethernet)規定,一組電訊號構成一個資料包,叫做幀(Frame)。每一幀分成兩部分:標頭和資料。標頭的長度固定為14位元組,資料的長度範圍為46~1500位元組,如果資料不夠長,則需要填充(比如ARP、RARP),如果過長,就必須分割成多個幀進行傳輸。

乙太網幀格式

標頭固定的14位元組為:目的地址(6個位元組)、源地址(6個位元組)和型別(2個位元組)。目的地址/源地址為MAC地址,型別:0x0800 是IP資料包,0x0806 是ARP請求,0x8035 是 RARP。末尾的CRC是校驗碼。

乙太網是採用廣播的形式傳送資料包的。比如,一個子網路中有3臺計算機,1號計算機想給2號計算機傳送一個資料包,2號、3號計算機都會收到這個包,然後讀取這個包的標頭,獲取目的MAC地址,和自身的MAC地址做匹配,如果相同則接收這個包,否則就丟棄這個包。

從上述廣播可以看出,乙太網資料包必須知道對方的MAC地址才可以傳輸資料,那麼一個網路卡是如何知道另一個網路卡的MAC地址的呢?其實就是通過ARP協議獲得的,後續文中將會說明。

網路層

又名網路互聯層。用來處理在網路上流動的資料包。

IP協議

網際網路是無數子網路共同組成的一個巨型網路。同一個子網路之間傳輸資料用MAC地址通過廣播的方式傳輸,那麼不同子網路之間呢?

網路層的誕生就是要引進一套新的地址,使得我們能夠區分不同的計算機是否資料同一個子網路。

規定網路地址的協議,叫做IP協議,它所定義的地址稱為IP地址。目前廣泛採用的是IP協議第四版,簡稱IPv4。這個版本規定,網路地址由32個二進位制位組成。習慣上,我們分成四段的十進位制數表示IP地址,從0.0.0.0到255.255.255.255。

IP地址分為兩個部分,前一部分代表網路,後一部分代表主機。但是單從IP地址我們無法判斷網路部分到底是前24位還是前16位等等,這時候就需要用到子網掩碼(subnet mask)了。所謂子網掩碼就是表示子網路特徵的一個引數。它在形式上等同與IP地址,也是一個32位二進位制數,它的網路部分全部為1,主機部分全部為0。比如,IP地址為192.168.1.1,如果已知網路部分是前24位,主機部分是後8位,那麼子網掩碼就是11111111.11111111.11111111.00000000,對應十進位制就是255.255.255.0。將兩個IP地址分別和子網掩碼進行AND運算,然後比較結果是否相同,就可以判斷兩個IP是否屬於一個子網路了。

IP資料包格式

IP資料包格式

IP資料包的首部長度和資料長度都是可變長的,但總是4位元組的整數倍。對於IPv4,4位版本欄位是4。4位首部長度是以4位元組為單位的,最小值是5,也就是說首部長度最小是4*5=20位元組,也就是不帶任何選項的IP首部,4位能表示的最大值是15,也就是說首部長度最大是60位元組。

8位TOS欄位有3個位用來指定IP資料包的優先順序(目前已經廢棄不用),還有4個位表示可選的服務型別(最小延遲、最大吞吐量、最小成本),還有一個位總是0。16位總長度是整個資料包(包括IP首部和IP層payload)的位元組數,最大是65535位元組,上面提到過乙太網資料幀的資料部分最大為1500位元組,因此,如果IP資料包超過了1500位元組,就需要分割成幾個乙太網資料幀進行傳輸。

每傳一個IP資料包,16位的標示增加1,可用於分片和重新組裝資料包。3位標誌和13位片偏移用於分片。

TTL(time to live)是這樣用的:源主機為資料包設定一個生存時間,比如64,每過一個路由器就把該值減1,如果減到0就表示路由已經太長了仍然找不到目的主機的網路,就丟棄該包,因此這個生存時間的單位不是秒,而是跳(hop)。協議欄位指示上層協議是TCP、UDP、ICMP還是IGMP。然後是校驗和,只校驗IP首部,資料的校驗由更高層協議負責。接下來是32位的IP地址。

ARP協議

看到這裡,就知道了要想往對方機器傳輸資料需要IP地址和MAC地址,IP地址可以通過DNS服務獲得,而MAC地址怎麼獲取呢?

這裡需要分兩種情況:

第一種情況,如果兩臺主機不在同一個子網路,其實是沒有辦法得到對方的MAC地址的,只能把資料包傳送到兩個子網路接處的閘道器(getaway),讓閘道器去處理。

第二種情況,如果兩臺主機在同一個子網路,那麼我們可以通過ARP協議,得到對方的MAC地址。簡單來說就是在乙太網首部目的MAC地址裡面填寫FF:FF:FF:FF:FF:FF,表示這是一個廣播地址。收到這個廣播的主機就會去匹配自己的IP地址,如果匹配則回覆自己的MAC地址,否則丟棄這個包。

傳輸層

對應用層提供處於網路連線中兩臺計算機的資料傳輸。網路層是主機到主機之間的通訊,而傳輸層是建立埠到埠的通訊。代表:UDP、TCP。

UDP

UDP段格式

UDP 首部比較簡單,總共8位元組。具體見上圖。

TCP

TCP段格式

和UDP協議一樣也有源埠號和目的埠號,通訊的雙方由IP地址和埠號標示。32位序號、32位確認號、視窗大小稍後詳細解釋。4位首部長度和IP協議頭類似,標示TCP協議頭的長度,如果沒有選項欄位,TCP協議頭最短為20位元組。URG、ACK、PSH、RST、SYN、FIN是六個控制位,稍後將解釋SYN、ACK、FIN、RST,其它從略。

看一個簡單的一問一答的例子:

TCP連線建立斷開

三次握手

  1. 客戶端發出段1(Client:SYN_SEND),標誌位是SYN,序號是1000,這個序號在網路通訊中用作臨時的地址,每傳送一個資料位元組,這個序號要加1,這樣在接收端可以根據序號排出資料包的正確順序,也可以發現丟包的情況,另外,規定SYN位和FIN位也要佔一個序號,這次雖然沒有發資料,但是由於傳送了SYN位,因此下次再傳送應該用序號1001。mss表示最大段尺寸,如果一個段太大,封裝成幀後超過了鏈路層的最大幀長度,就必須在IP層分片,為了避免這種情況,客戶端生命自己的最大段尺寸,建議伺服器端發來的段不要超過這個長度。

  2. 伺服器發出段2(Server:SYN_RECV),也帶有SYN位,同時置ACK位表示確認,確認序號是1001,表示“我接收到序號1000及其以前所有的段,請你下次傳送序號位1001的段”,也就是應答了客戶端的連線請求,同時也給客戶端發出一個連線請求,同時宣告最大尺寸為1024。

  3. 客戶端發出段3(ESTABLISHED),對伺服器的連線請求進行應答,確認序號是8001。

在TCP通訊中,如果一方接收到另一方發來的段,讀出其中的目的埠號,發現本機並沒有任何程式使用這個埠,就會應答一個包含RST位的段給另一方。

資料傳輸

  1. 客戶端發出段4,包含從序號1001開始的20個位元組資料。
  2. 伺服器發出段5,確認序號為1021,對序號1001-1020的資料表示確認收到,同時請求傳送序號1021開始的資料,伺服器在應答的同時也向客戶端傳送從序號8001開始的10個位元組資料,這稱之為piggyback。
  3. 客戶端發出段6,對伺服器發來的序號8001-8010的資料表示確認收到,請求傳送序號8001開始的資料。

在資料傳輸過程中,ACK和確認序號是非常重要的,應用層交給TCP協議傳送的資料會暫存在TCP層的傳送緩衝區中,發出資料之後,只有收到了對方的應答ACK段,才確認資料是成功傳送了,並從快取區中移除。如果等待超時,會進行重發。

四次揮手

  1. 客戶端發出段7(Client:FIN_WAIT_1),FIN位表示關閉連線的請求。
  2. 伺服器發出段8(Server:COSE_WAIT, Client:FIN_WAIT_2),應答客戶端的關閉連線請求。
  3. 伺服器發出段9(Server:LAST_ACK),其中也包含FIN位,向客戶端傳送關閉連線的請求。
  4. 客戶端發出段10(Client:TIME_WAIT)應答伺服器的關閉連線請求。

建立連線是三次握手,而關閉通常連線需要四段(也有三次的情況),伺服器的應答和關閉連線請求通常不合並在一個段中,因為有連線半關閉的情況,這種情況下客戶端關閉連線之後就不能再傳送資料給伺服器了,但是伺服器還可以傳送資料給客戶端,直到伺服器也關閉連線為止。

客戶端發出段10之後,不是立馬關閉連線,而是進入TIME_WAIT狀態,等待2MSL。MSL是Maximum Segment Lifetime的縮寫,表示報文最大生存時間,當段10由於網路原因沒有成功傳送時,經過1MSL伺服器會重發段9,段9傳輸最慢需要1MSL,所以需要等待2MSL來確保最後一次ACK成功傳送。

滑動視窗

我們知道UDP協議是不可靠的,當傳送端傳送的速度過快,接收端收到資料後處理的速度較慢,而緩衝區大小是固定的,就會丟失資料。TCP協議通過滑動視窗(Sliding Window)機制解決這一問題。

滑動視窗

  1. 傳送端發起連線,宣告最大尺寸是1460,初始序號是0,視窗大小是4K,表示“我的接收緩衝區還有4K位元組空閒,你發的資料不要超過4K”。接收端應答連線請求,宣告最大段尺寸是1024,初始序號是8000,視窗大小是6K。傳送端應答,三次握手結束。

  2. 傳送端發出段4-9,每個段帶1K的資料,傳送端根據視窗大小知道接收端的緩衝區滿了,因此停止傳送資料。

  3. 接收端的應用程式提走2K資料,接收緩衝區又有了2K的空閒,接收端傳送段10,在應答已收到6K資料的同時宣告視窗大小為2K。

  4. 接收端的應用程式又提走2K資料,接收緩衝區有4K空閒,接收端發出段11,重新宣告視窗大小為4K。

  5. 傳送端發出段12-13,每個段帶2K的資料,段13同時還包含FIN位。

  6. 接收端應答接收到的2K資料(6145-8192),再加上FIN位佔一個序號8193,因此應答序號是8194,連線處於半關閉狀態,接收端同時宣告視窗大小為2K。

  7. 接收端的應用程式提走2K資料,接收端重新宣告視窗大小為4K。

  8. 接收端的應用程式提走剩下的2K資料,接收緩衝區全空,接收端重新宣告視窗大小為6K。

  9. 接收端的應用程式在提走全部資料後,決定關閉連線,發出段17包含FIN位,傳送端應答,連線完全關閉。

應用層

就是平時接觸最多的一層,比如HTTP、DNS、FTP。

以 HTTP 為例,為了傳輸方便在傳輸層(TCP協議)把從應用層收到的資料(HTTP報文)進行分割,並在各個報文上打上標記序號及埠號後轉發給網路層。

在網路層(IP協議),增加作為通訊目的地的 MAC 地址後轉發給鏈路層。

接收端的伺服器在鏈路層收到資料,按序往上層傳送,一直到應用層。

HTTP傳輸示例

HTTP 狀態碼

下面?的表格列出了常見的 HTTP 狀態碼

網路、HTTP相關學習總結
HTTP狀態碼302、303和307的故事

HTTP/2

HTTP/2,簡稱h2(基於TLS/1.2或以上版本的加密連線)或h2c(非加密連線),是 HTTP 協議的第二個主要版本,主要基於 SPDY 協議。

SPDY 由 Google 研發,基於傳輸控制協議(TCP)的應用層協議,其主要設計目的是降低網頁載入時間。通過優先順序和多路複用,SPDY 使得只需要建立一個 TCP 連線即可傳送網路內容和圖片資源。SPDY 中廣泛應用了 TLS 加密,傳輸內容也均以 gzip 或者 DEFLATE 格式壓縮,另外 SPDY 還支援服務端主動推送資料到客戶端。

HTTP/2 和 SPDY 的不同點

  1. HTTP/2 支援明文傳輸,而 SPDY 強制使用 TLS 加密。
  2. HTTP/2 頭壓縮使用的演算法是 HPACK,而 SPDY 使用的是 DEFLATE

HTTP/2 的優點

1. 幀、訊息和流

HTTP/2 採用了二進位制而非文字來進行傳輸資料,這也是和 HTTP/1.x 的最大區別。HTTP/2 將一個 TCP 連線分為若干個流(Stream),每一個流中可以傳輸若干個訊息(Message),每一個訊息由若干個最小的二進位制幀(Frame)組成。

網路、HTTP相關學習總結

流(Stream)

如上圖所示,流一般表示的是每個請求和響應,在 HTTP/2 中可以多個流同時傳輸。

訊息(Message)

訊息是一組幀,表示某一個具體的請求或者響應。

幀(Frame)

幀是 HTTP/2 資料傳輸中的最小單位。每一幀都包含標頭和資料,頭部(固定9個位元組)整個幀格式如下:

    +-----------------------------------------------+
    |                 Length (24)                   |
    +---------------+---------------+---------------+
    |   Type (8)    |   Flags (8)   |
    +-+-------------+---------------+-------------------------------+
    |R|                 Stream Identifier (31)                      |
    +=+=============================================================+
    |                   Frame Payload (0...)                      ...
    +---------------------------------------------------------------+
複製程式碼
  • length 佔3個位元組表示的是整個幀的大小。

  • type 表示型別,目前規定了10種型別,具體如下:

    • 0x0:DATA 資料幀型別
    • 0x1:HEADERS 請求頭型別
    • 0x2:PRIORITY 設定流的優先順序
    • 0x3:RST_STREAM 終止流
    • 0x4:SETTINGS 設定此連線的引數
    • 0x5:PUSH_PROMISE 伺服器推送
    • 0x6:PING 測試 RTT
    • 0x7:GOAWAY 終止連線
    • 0x8:WINDOW_UPDATE 流量控制
    • 0x9:CONTINUATION 繼續傳輸頭部資料
  • flag 是標誌位,常見的有 END_STREAM 、 END_HEADERS 和 PADDED。詳細參加這裡

  • R 是保留位

  • identifier 標示符,用於跟蹤邏輯流的幀成員關係。簡單的說就是標示的哪個流。

網路、HTTP相關學習總結

2.多路複用

知道了上述流的概念之後,多路複用就好理解了。HTTP/1.0 每次都需要經過三次握手才可以傳輸資料,HTTP/1.1 中雖然增加了keep-alive可以不用每次建立連線,但是還是需要等待上一個響應返回之後,才可以傳送新的請求,而在 HTTP/2.0 中只增加請求只需要增加一個流即可,資料流以訊息的形式傳送,而訊息又由一個或多個幀組成,多個幀之間可以亂序傳送。

網路、HTTP相關學習總結

3.優先順序排序

由於可以進行多路複用,伺服器和客戶端的幀都是交錯傳送的,對於傳送給伺服器的幀,為了解決處理的先後問題,因此引入了資料流的優先順序。通過優先順序型別(PRIORITY)的幀或者標頭幀可以給流設定優先順序。也可以定義依賴關係,允許在一個資源之前載入另一個資源。還可以將優先順序組合到一個依賴樹中,讓開發者控制每個流的重要性。

優先順序依賴樹

在上圖?中,字母標示流標示符,數字表示分配給每個流的權重。樹的根是流 A,首先會向它分配資源,然後才向依賴它的流 B 和 C 分配資源。為流 B 分配了 40% 的權重,流 C 分配了 60% 的權重,即流 B 和 C 分別佔用 40% 和 60% 的可用資源。依次往下。

4.頭壓縮

專門為 HTTP/2 定製的 HPACK 演算法為頭壓縮提供了很好的支援。它使用了一份 索引表 來定義常用的 HTTP Header,把常用的 HTTP Header 存放在表裡,請求的時候只需要傳送對應的索引即可,舉個? :method=GET 對應索引值為2,path=/index.html 索引值為5。那麼只需要給服務端傳送一個 Frame,該 Frame 的 payload 是 0x8285,Frame 的 type 設定為 HEADERS 型別,便可以知道這是一個請求頭,內容是 GET /index.html。既節儉了流量,又提高了傳輸效率。

0x8285 而不是 0x0205?這是因為高位設定為1表示這個位元組是一個完全索引值(key 和 value 都在索引中)。類似的,通過高位的標誌位可以區分出這個位元組是屬於一個完全索引值,還是僅索引了key,還是 key 和 value 都沒有索引。(具體可以看下這篇文章(1.3 首部欄位及首部塊的表示))因為索引表的大小是有限的,它僅儲存了一些常用的 HTTP Header,同時每次請求還可以在表尾動態追加新的 HTTP Header 快取。動態部分稱之為 Dynamic Table。Static Table 和 Dynamic Table 在一起組成了索引表。

<----------  Index Address Space ---------->
<-- Static  Table -->  <-- Dynamic Table -->
+---+-----------+---+  +---+-----------+---+
| 1 |    ...    | s |  |s+1|    ...    |s+k|
+---+-----------+---+  +---+-----------+---+
                       ^                   |
                       |                   V
                 Insertion Point      Dropping Point
複製程式碼

HPACK 不僅通過索引值來降低資料量,同時還會將字串進行 霍夫曼編碼 來壓縮字串的大小。

網路、HTTP相關學習總結

5.服務端推送

作為 HTTP/2 的一個重磅功能,也不是伺服器想推就可以推的,伺服器要遵循請求-響應這個模型,只不過伺服器對同一個請求可以推送多個響應。客戶端在交換 SETTINGS Frame 時,設定欄位 SETTINGS_ENABLE_PUSH (0x2) 為1顯示允許伺服器推送。

當服務端需要主動推送某個資源時,便會傳送一個 Frame type 為 PUSH_PROMISE 的 Frame,裡面帶了 PUSH 需要新建的 Stream ID。意思時告訴客戶端“接下來我要用這個ID向你傳送東西,你準好接著”。

參考:

圖解 HTTP

OSI模型

HTTP/2

TCP/IP協議基礎

SPDY

HTTP/2 幕後原理

HTTP/2 新特性淺析

相關文章