世界上幾乎全部的 HTTP 通訊都是由 TCP/IP 承載的,TCP/IP 是全球計算機及網絡設備都 在使用的一種經常使用的分組交換網絡分層協議集。客戶端應用程序能夠打開一條 TCP/IP 連 接,鏈接到可能運行在世界任何地方的服務器應用程序。一旦鏈接創建起來了,在客戶端 和服務器的計算機之間交換的報文就永遠不會丟失、受損或失序。程序員
儘管報文不會丟失或受損,但若是計算機或網絡崩潰了,客戶端和服務器之間的通訊仍然會被斷開。在這種狀況下, 會通知客戶端和服務器通訊中斷了。編程
當瀏覽器收到一個 URL 的時候,會執行幾個相對應的步驟,以下瀏覽器
瀏覽器解析出主機名;緩存
瀏覽器查詢主機名的 IP 地址;安全
瀏覽器得到端口號;性能優化
瀏覽器發起對該 IP 地址對應端口號的連接;服務器
瀏覽器向服務器發送一條 HTTP GET報文;網絡
瀏覽器從服務器讀取 HTTP 相應報文;數據結構
1.一、TCP 鏈接的基本知識併發
TCP 是可靠的數據管道
TCP 會按序、無差錯地承載 HTTP 數據,TCP 爲 HTTP 提供了一條可靠的比特傳輸管道。從 TCP 鏈接一端填入的字節會從另外一端 以原有的順序、正確地傳送出來。
TCP 流是分段的、由 IP 分組傳送
TCP 的數據是經過名爲 IP 分組(或 IP 數據報)的小數據塊來發送的。
這樣的話,如圖 HTTP 就是 「HTTP over TCP over IP」 這個「協議棧」中的最頂層了。其安全版本 HTTPS 就是在 HTTP 和 TCP 之間插入了一個(稱爲 TLS 或 SSL 的)密碼加密層(安全層),就是在圖中的右半部分。
HTTP 要傳送一條報文時,會以流的形式將報文數據的內容經過一條打開的 TCP 鏈接按 序傳輸。TCP 收到數據流以後,會將數據流砍成被稱做段的小數據塊,並將段封裝在 IP 分組中,經過因特網進行傳輸,以下圖中你們看到的內容:
每一個 TCP 段都是由 IP 分組承載,從一個 IP 地址發送到另外一個 IP 地址的。
而每一個 IP 分組中都包括:
一個 IP 分組首部(一般爲 20 字節);
一個 TCP 段首部(一般爲 20 字節);
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 套接字接口進行通訊的
上圖中說明了能夠怎樣經過套接字 API 來凸顯客戶端和服務器在實現 HTTP 事務時所應執行的步驟。
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 中有一些能夠重用現存鏈接 的工具。
前面咱們說了 TCP 鏈接,咱們從新來分析一下 HTTP ,以前我也說過在 HTTP 1.0的時候和1.1以後,有 Keep-Alive ,關於 Keep-Alive 不懂的請翻看前面的公衆號的文章內容,接下來我分幾個內容給你們講述 HTTP 對鏈接上的處理。
並行鏈接:經過多條 TCP 鏈接發起併發的 HTTP 請求。
持久鏈接:重用 TCP 鏈接,以消除鏈接及關閉時延。
咱們來看一下串行:
每一個事務都須要(串行地創建)一條 新的鏈接,那麼鏈接時延和慢啓動時延就會疊加起來
並行鏈接就是說 HTTP 容許客戶端打開多條鏈接,並行的去執行多個 HTTP 的事務,就會出現多條線路平行的狀況。
其實並行鏈接並無說是頁面的傳輸速度,是由於多個對象同時在進展,因此,他的速度要比疊加起來,讓你在感受上快很多。
持久鏈接
HTTP 1.1 容許 HTTP 設備在事務處理結束以後 將 TCP 鏈接保持在打開狀態,以便爲將來的 HTTP 請求重用現存的鏈接。在事務處理結束以後仍然保持在打開狀態的 TCP 鏈接被稱爲持久鏈接。非持久鏈接會在每一個事務結束以後關閉。持久鏈接會在不一樣事務之間保持打開狀態,直到客戶端或服務器決定將其關閉爲止。
管道化鏈接(也有人稱之爲管線化)
HTTP/1.1 容許在持久鏈接上可選地使用請求管道。這是相對於 keep-alive 鏈接的又一性能優化。在響應到達以前,能夠將多條請求放入隊列。當第一條請求經過網絡流向地球另外一端的服務器時,第二條和第三條請求也能夠開始發送了。在高時延網絡條件下,這樣作能夠下降網絡的環回時間,提升性能。
其實管道化說白了就是 傳送過程當中不需先等待服務端的迴應,而後又發了幾條,瀏覽器將 HTTP 要求大批提交可大幅縮短頁面的加載時間,特別是在傳輸延遲(lag/latency)較高的狀況下(如衛星鏈接)。此技術之關鍵在於多個 HTTP 的要求消息能夠同時塞入一個 TCP 分組中,因此只提交一個分組便可同時發出多個要求,藉此可減小網絡上多餘的分組並下降線路負載。