之前我寫了篇關于 HTTP 的文章,文章中講述了 HTTP的特點,HTTP 的報文,HTTP 的請求方式等知識,接下來,深入了,我們就關于 HTTP 引發的面試題來進行入手,一起來看一下吧!
1. HTTP 是如何使用 TCP 連接的;
世界上幾乎所有的 HTTP 通信都是由 TCP/IP 承載的,TCP/IP 是全球計算機及網絡設備都 在使用的一種常用的分組交換網絡分層協議集。客戶端應用程序可以打開一條 TCP/IP 連 接,連接到可能運行在世界任何地方的服務器應用程序。一旦連接建立起來了,在客戶端 和服務器的計算機之間交換的報文就永遠不會丟失、受損或失序。
盡管報文不會丟失或受損,但如果計算機或網絡崩潰了,客戶端和服務器之間的通信仍然會被斷開。在這種情況下, 會通知客戶端和服務器通信中斷了。
當浏覽器收到一個 URL 的時候,會執行幾個相對應的步驟,如下
- 浏覽器解析出主機名;
- 浏覽器查詢主機名的 IP 地址;
- 浏覽器獲得端口號;
- 浏覽器發起對該 IP 地址對應端口號的鏈接;
- 浏覽器向服務器發送一條 HTTP GET報文;
- 浏覽器從服務器讀取 HTTP 相應報文;
- 浏覽器關閉連接;
TCP 會按序、無差錯地承載 HTTP 數據,TCP 爲 HTTP 提供了一條可靠的比特傳輸管道。從 TCP 連接一端填入的字節會從另一端 以原有的順序、正確地傳送出來。
TCP 流是分段的、由 IP 分組傳送
TCP 的數據是通過名爲 IP 分組(或 IP 數據報)的小數據塊來發送的。
每個 TCP 段都是由 IP 分組承載,從一個 IP 地址發送到另一個 IP 地址的。
而每個 IP 分組中都包括:
- 一個 IP 分組首部(通常爲 20 字節);
- 一個 TCP 段首部(通常爲 20 字節);
- 一個 TCP 數據塊(0 個或多個字節)。
IP 首部包含了源和目的 IP 地址、長度和其他一些標記。TCP 段的首部包含了 TCP 端口 號、TCP 控制標記,以及用于數據排序和完整性檢查的一些數字值。
保持 TCP 連接的持續不間斷地運行
在任意時刻計算機都可以有幾條 TCP 連接處于打開狀態。TCP 是通過端口號來保持所有 這些連接的正確運行的。 端口號和雇員使用的電話分機號很類似。
這就和我之前舉得例子是一樣的,公司的總機和你自己的座機一樣,公司的總機號碼能將你接到前台,而分機號 可以將你接到正確的雇員位置一樣,IP 地址可以將你連接到正確的計算機,而端口號則 可以將你連接到正確的應用程序上去。TCP 連接是通過 4 個值來識別的:
源IP 地址、源端口號、目的IP 地址、目的端口號
這 4 個值一起唯一地定義了一條連接。兩條不同的 TCP 連接不能擁有 4 個完全相同的地 址組件值(但不同連接的部分組件可以擁有相同的值)。
這裏需要我們注意的是,有些連接共享了相同的目的端口號,有些連接使用了相同的源 IP 地址,有些使用了相同的目的 IP 地址,但沒有兩個不同連接所有的 4 個值都一樣。
TCP 套接字
操作系統提供了一些操縱其 TCP 連接的工具。爲了更具體地說明問題,我們來看一個 TCP 編程接口,這些套接字我就不一一介紹了,我給大家一個表格,大家可以理解一下
套接字API調用描 述s = socket()創建一個新的、未命名、未關聯的套接字bind(s,)向套接字賦一個本地端口號和接口connect(s, )創建一條連接本地套接字與遠程主機及端口的連接listen(s,…)標識一個本地套接字,使其可以合法接受連接s2 = accept(s)等待某人建立一條到本地端口的連接
套接字 API 允許用戶創建 TCP 的端點數據結構,將這些端點與遠程服務器的 TCP 端點進 行連接,並對數據流進行讀寫。TCP API 隱藏了所有底層網絡協議的握手細節,以及 TCP 數據流與 IP 分組之間的分段和重裝細節。
TCP 客戶端和服務器是如何通過 TCP 套接字接口進行通信的
- 請求新的 TCP 連接時,客戶端要向服務器發送一個小的 TCP 分組(通常是 40 ~ 60 個字節)。這個分組中設置了一個特殊的 SYN 標記,說明這是一個連接請求。
- 如果服務器接受了連接,就會對一些連接參數進行計算,並向客戶端回送一個 TCP 分組,這個分組中的 SYN 和 ACK 標記都被置位,說明連接請求已被接受。
- 最後,客戶端向服務器回送一條確認信息,通知它連接已成功建立
我們永遠不會看到這些分組——這些分組都由 TCP/IP 軟件管理,對其是不可見 的。HTTP 程序員看到的只是創建 TCP 連接時存在的時延。
在這裏我們需要注意的就是 TCP 連接的握手時延,通常 HTTP 事務都不會交換太多數據,此時,SYN/SYN+ACK 握手(參見圖中的 a 段 和圖中的 b 段)會産生一個可測量的時延。TCP 連接的 ACK 分組(參見圖中的 c 段)通常都足夠大,可以承載整個 HTTP 請求報文,而且很多 HTTP 服務器響應報文都可 以放入一個 IP 分組 中去(比如,響應是包含了裝飾性圖片的小型 HTML 文件,或者是對浏覽器高速緩存請求産生的 304 Not Modified 響應)。
TCP 慢啓動
TCP 數據傳輸的性能還取決于 TCP 連接的使用期(age)。TCP 連接會隨著時間進行自 我“調諧”,起初會限制連接的最大速度,如果數據成功傳輸,會隨著時間的推移提高傳輸 的速度。這種調諧被稱爲 TCP 慢啓動(slow start),用于防止因特網的突然過載和擁 塞。
TCP 慢啓動限制了一個 TCP 端點在任意時刻可以傳輸的分組數。簡單來說,每成功接收 一個分組,發送端就有了發送另外兩個分組的權限。如果某個 HTTP 事務有大量數據要發 送,是不能一次將所有分組都發送出去的。必須發送一個分組,等待確認;然後可以發送 兩個分組,每個分組都必須被確認,這樣就可以發送四個分組了,以此類推。這種方式被 稱爲“打開擁塞窗口”。
由于存在這種擁塞控制特性,所以新連接的傳輸速度會比已經交換過一定量數據的、“已 調諧”連接慢一些。由于已調諧連接要更快一些,所以 HTTP 中有一些可以重用現存連接 的工具。
3. HTTP 連接的處理
前面我們說了 TCP 連接,我們重新來分析一下 HTTP ,之前我也說過在 HTTP 1.0的時候和1.1之後,有 Keep-Alive ,關于 Keep-Alive 不懂的請翻看前面的公衆號的文章內容,接下來我分幾個內容給大家講述 HTTP 對連接上的處理。
- 並行連接1 通過多條 TCP 連接發起並發的 HTTP 請求。
- 持久連接1 重用 TCP 連接,以消除連接及關閉時延。
- 管道化連接1 通過共享的 TCP 連接發起並發的 HTTP 請求。
我們來看一下串行:
其實並行連接並沒有說是頁面的傳輸速度,是因爲多個對象同時在進展,所以,他的速度要比疊加起來,讓你在感覺上快不少。
持久連接
HTTP 1.1 允許 HTTP 設備在事務處理結束之後 將 TCP 連接保持在打開狀態,以便爲未來的 HTTP 請求重用現存的連接。在事務處理結束之後仍然保持在打開狀態的 TCP 連接被稱爲持久連接。非持久連接會在每個事務結束之後關閉。持久連接會在不同事務之間保持打開狀態,直到客戶端或服務器決定將其關閉爲止。
關于持久連接上一篇文章已經描述的很清楚了,文章鏈接封上【http://www.justdojava.com/2019/10/13/java-Http2/】
管道化連接(也有人稱之爲管線化)
HTTP/1.1 允許在持久連接上可選地使用請求管道。這是相對于 keep-alive 連接的又一性能優化。在響應到達之前,可以將多條請求放入隊列。當第一條請求通過網絡流向地球另一端的服務器時,第二條和第三條請求也可以開始發送了。在高時延網絡條件下,這樣做可以降低網絡的環回時間,提高性能。
其實管道化說白了就是 傳送過程中不需先等待服務端的回應,然後又發了幾條,浏覽器將 HTTP 要求大批提交可大幅縮短頁面的加載時間,特別是在傳輸延遲(lag/latency)較高的情況下(如衛星連接)。此技術之關鍵在于多個 HTTP 的要求消息可以同時塞入一個 TCP 分組中,所以只提交一個分組即可同時發出多個要求,借此可減少網絡上多余的分組並降低線路負載。
關于 HTTP 的連接我們就先介紹到這裏吧,下一篇文章我們將繼續講述 關于代理的那點事!