可能會搞砸你的面試:你知道一個TCP連線上能發起多少個HTTP請求嗎?

JackJiang發表於2019-08-02

本文由原作者鬆若章原創釋出,作者主頁:zhihu.com/people/hrsonion/posts,感謝原作者的無私分享。

1、引言

一道經典的面試題是:從 URL 在瀏覽器被被輸入到頁面展現的過程中發生了什麼?

大多數回答都是說請求響應之後 DOM 怎麼被構建,被繪製出來。但是你有沒有想過,收到的 HTML 如果包含幾十個圖片標籤,這些圖片是以什麼方式、什麼順序、建立了多少連線、使用什麼協議被下載下來的呢?

要搞懂這個問題,我們需要先解決下面五個問題:

1)現代瀏覽器在與伺服器建立了一個 TCP 連線後是否會在一個 HTTP 請求完成後斷開?什麼情況下會斷開?

2)一個 TCP 連線可以對應幾個 HTTP 請求?

3)一個 TCP 連線中 HTTP 請求傳送可以一起傳送麼(比如一起發三個請求,再三個響應一起接收)?

4)為什麼有的時候重新整理頁面不需要重新建立 SSL 連線?

5)瀏覽器對同一 Host 建立 TCP 連線到數量有沒有限制?

好了,帶著上面的問題,我來閱讀本文內容。

(本文同步釋出於:www.52im.net/thread-2680…

2、相關文章

3、第一個問題:與伺服器建立的連線是否會在一個HTTP請求後斷開?什麼情況下斷開?

如題所示,先來談談第一個問題:現代瀏覽器在與伺服器建立了一個 TCP 連線後是否會在一個 HTTP 請求完成後斷開?什麼情況下會斷開?

在 HTTP/1.0 中,一個伺服器在傳送完一個 HTTP 響應後,會斷開 TCP 連結。但是這樣每次請求都會重新建立和斷開 TCP 連線,代價過大。所以雖然標準中沒有設定,某些伺服器對 Connection: keep-alive 的 Header 進行了支援。意思是說,完成這個 HTTP 請求之後,不要斷開 HTTP 請求使用的 TCP 連線。這樣的好處是連線可以被重新使用,之後傳送 HTTP 請求的時候不需要重新建立 TCP 連線,以及如果維持連線,那麼 SSL 的開銷也可以避免。

下面兩張圖片是我短時間內兩次訪問 www.github.com 的時間統計:

可能會搞砸你的面試:你知道一個TCP連線上能發起多少個HTTP請求嗎?

▲ 頭一次訪問,有初始化連線和 SSL 開銷

可能會搞砸你的面試:你知道一個TCP連線上能發起多少個HTTP請求嗎?

▲ 初始化連線和 SSL 開銷消失了,說明使用的是同一個 TCP 連線

持久連線:既然維持 TCP 連線好處這麼多,HTTP/1.1 就把 Connection 頭寫進標準,並且預設開啟持久連線,除非請求中寫明 Connection: close,那麼瀏覽器和伺服器之間是會維持一段時間的 TCP 連線,不會一個請求結束就斷掉。

所以第一個問題的答案是:預設情況下建立 TCP 連線不會斷開,只有在請求報頭中宣告 Connection: close 才會在請求完成後關閉連線。(詳細文件請見:tools.ietf.org/html/rfc261…

4、第二個問題:一個 TCP 連線可以對應幾個 HTTP 請求?

瞭解了第一個問題之後,其實這個問題已經有了答案:如果維持連線,一個 TCP 連線是可以傳送多個 HTTP 請求的。

5、第三個問題:一個 TCP 連線中 HTTP 請求傳送可以一起傳送麼?

再來看看第三個問題:一個 TCP 連線中 HTTP 請求傳送可以一起傳送麼(比如一起發三個請求,再三個響應一起接收)?

HTTP/1.1 存在一個問題:單個 TCP 連線在同一時刻只能處理一個請求。

意思是說:兩個請求的生命週期不能重疊,任意兩個 HTTP 請求從開始到結束的時間在同一個 TCP 連線裡不能重疊。

雖然 HTTP/1.1 規範中規定了 Pipelining 來試圖解決這個問題,但是這個功能在瀏覽器中預設是關閉的。

先來看一下 Pipelining 是什麼,RFC 2616 中規定了:

原文:A client that supports persistent connections MAY "pipeline" its requests (i.e., send multiple requests without waiting for each response). A server MUST send its responses to those requests in the same order that the requests were received.

翻譯:一個支援持久連線的客戶端可以在一個連線中傳送多個請求(不需要等待任意請求的響應)。收到請求的伺服器必須按照請求收到的順序傳送響應。

至於標準為什麼這麼設定,我們可以大概推測一個原因:由於 HTTP/1.1 是個文字協議,同時返回的內容也並不能區分對應於哪個傳送的請求,所以順序必須維持一致。比如你向伺服器傳送了兩個請求 GET /query?q=A 和 GET /query?q=B,伺服器返回了兩個結果,瀏覽器是沒有辦法根據響應結果來判斷響應對應於哪一個請求的。

Pipelining 這種設想看起來比較美好,但是在實踐中會出現許多問題:

1)一些代理伺服器不能正確的處理 HTTP Pipelining;

2)正確的流水線實現是複雜的。詳見《HTTP/1.x 的連線管理》;

3)Head-of-line Blocking 連線頭阻塞:在建立起一個 TCP 連線之後,假設客戶端在這個連線連續向伺服器傳送了幾個請求。按照標準,伺服器應該按照收到請求的順序返回結果,假設伺服器在處理首個請求時花費了大量時間,那麼後面所有的請求都需要等著首個請求結束才能響應。

所以現代瀏覽器預設是不開啟 HTTP Pipelining 的。

但是,HTTP2 提供了 Multiplexing 多路傳輸特性,可以在一個 TCP 連線中同時完成多個 HTTP 請求。至於 Multiplexing 具體怎麼實現的就是另一個問題了。我們可以看一下使用 HTTP2 的效果。

可能會搞砸你的面試:你知道一個TCP連線上能發起多少個HTTP請求嗎?

▲ 綠色是發起請求到請求返回的等待時間,藍色是響應的下載時間,可以看到都是在同一個 Connection,並行完成的

所以這個問題也有了答案:在 HTTP/1.1 存在 Pipelining 技術可以完成這個多個請求同時傳送,但是由於瀏覽器預設關閉,所以可以認為這是不可行的。在 HTTP2 中由於 Multiplexing 特點的存在,多個 HTTP 請求可以在同一個 TCP 連線中並行進行。

那麼在 HTTP/1.1 時代,瀏覽器是如何提高頁面載入效率的呢?

主要有下面兩點:

1)維持和伺服器已經建立的 TCP 連線,在同一連線上順序處理多個請求;

2)和伺服器建立多個 TCP 連線。

6、第四個問題:為什麼有的時候重新整理頁面不需要重新建立 SSL 連線?

在第一個問題的討論中已經有答案了:TCP 連線有的時候會被瀏覽器和服務端維持一段時間。TCP 不需要重新建立,SSL 自然也會用之前的。

7、第五個問題:瀏覽器對同一 Host 建立 TCP 連線到數量有沒有限制?

假設我們還處在 HTTP/1.1 時代,那個時候沒有多路傳輸,當瀏覽器拿到一個有幾十張圖片的網頁該怎麼辦呢?

肯定不能只開一個 TCP 連線順序下載,那樣使用者肯定等的很難受,但是如果每個圖片都開一個 TCP 連線發 HTTP 請求,那電腦或者伺服器都可能受不了,要是有 1000 張圖片的話總不能開 1000 個TCP 連線吧,你的電腦同意 NAT 也不一定會同意。

所以答案是:有。Chrome 最多允許對同一個 Host 建立六個 TCP 連線。不同的瀏覽器有一些區別,詳見:developers.google.com/web/tools/c…

那麼回到最開始的問題:收到的 HTML 如果包含幾十個圖片標籤,這些圖片是以什麼方式、什麼順序、建立了多少連線、使用什麼協議被下載下來的呢?

如果圖片都是 HTTPS 連線並且在同一個域名下,那麼瀏覽器在 SSL 握手之後會和伺服器商量能不能用 HTTP2,如果能的話就使用 Multiplexing 功能在這個連線上進行多路傳輸。不過也未必會所有掛在這個域名的資源都會使用一個 TCP 連線去獲取,但是可以確定的是 Multiplexing 很可能會被用到。

如果發現用不了 HTTP2 呢?或者用不了 HTTPS(現實中的 HTTP2 都是在 HTTPS 上實現的,所以也就是隻能使用 HTTP/1.1)。那瀏覽器就會在一個 HOST 上建立多個 TCP 連線,連線數量的最大限制取決於瀏覽器設定,這些連線會在空閒的時候被瀏覽器用來傳送新的請求,如果所有的連線都正在傳送請求呢?那其他的請求就只能等等了。

(原文連結:點此進入

附錄:更多網路程式設計基礎資料

TCP/IP詳解 - 第11章·UDP:使用者資料包協議
TCP/IP詳解 - 第17章·TCP:傳輸控制協議
TCP/IP詳解 - 第18章·TCP連線的建立與終止
TCP/IP詳解 - 第21章·TCP的超時與重傳
技術往事:改變世界的TCP/IP協議(珍貴多圖、手機慎點)
通俗易懂-深入理解TCP協議(上):理論基礎
通俗易懂-深入理解TCP協議(下):RTT、滑動視窗、擁塞處理
理論經典:TCP協議的3次握手與4次揮手過程詳解
理論聯絡實際:Wireshark抓包分析TCP 3次握手、4次揮手過程
計算機網路通訊協議關係圖(中文珍藏版)
UDP中一個包的大小最大能多大?
P2P技術詳解(一):NAT詳解——詳細原理、P2P簡介
P2P技術詳解(二):P2P中的NAT穿越(打洞)方案詳解
P2P技術詳解(三):P2P技術之STUN、TURN、ICE詳解
通俗易懂:快速理解P2P技術中的NAT穿透原理
高效能網路程式設計(一):單臺伺服器併發TCP連線數到底可以有多少
高效能網路程式設計(二):上一個10年,著名的C10K併發連線問題
高效能網路程式設計(三):下一個10年,是時候考慮C10M併發問題了
高效能網路程式設計(四):從C10K到C10M高效能網路應用的理論探索
高效能網路程式設計(五):一文讀懂高效能網路程式設計中的I/O模型
高效能網路程式設計(六):一文讀懂高效能網路程式設計中的執行緒模型
不為人知的網路程式設計(一):淺析TCP協議中的疑難雜症(上篇)
不為人知的網路程式設計(二):淺析TCP協議中的疑難雜症(下篇)
不為人知的網路程式設計(三):關閉TCP連線時為什麼會TIME_WAIT、CLOSE_WAIT
不為人知的網路程式設計(四):深入研究分析TCP的異常關閉
不為人知的網路程式設計(五):UDP的連線性和負載均衡
不為人知的網路程式設計(六):深入地理解UDP協議並用好它
不為人知的網路程式設計(七):如何讓不可靠的UDP變的可靠?
不為人知的網路程式設計(八):從資料傳輸層深度解密HTTP
網路程式設計懶人入門(一):快速理解網路通訊協議(上篇)
網路程式設計懶人入門(二):快速理解網路通訊協議(下篇)
網路程式設計懶人入門(三):快速理解TCP協議一篇就夠
網路程式設計懶人入門(四):快速理解TCP和UDP的差異
網路程式設計懶人入門(五):快速理解為什麼說UDP有時比TCP更有優勢
網路程式設計懶人入門(六):史上最通俗的集線器、交換機、路由器功能原理入門
網路程式設計懶人入門(七):深入淺出,全面理解HTTP協議
網路程式設計懶人入門(八):手把手教你寫基於TCP的Socket長連線
網路程式設計懶人入門(九):通俗講解,有了IP地址,為何還要用MAC地址?
技術掃盲:新一代基於UDP的低延時網路傳輸層協議——QUIC詳解
讓網際網路更快:新一代QUIC協議在騰訊的技術實踐分享
現代移動端網路短連線的優化手段總結:請求速度、弱網適應、安全保障
聊聊iOS中網路程式設計長連線的那些事
移動端IM開發者必讀(一):通俗易懂,理解行動網路的“弱”和“慢”
移動端IM開發者必讀(二):史上最全移動弱網路優化方法總結
IPv6技術詳解:基本概念、應用現狀、技術實踐(上篇)
IPv6技術詳解:基本概念、應用現狀、技術實踐(下篇)
從HTTP/0.9到HTTP/2:一文讀懂HTTP協議的歷史演變和設計思路
腦殘式網路程式設計入門(一):跟著動畫來學TCP三次握手和四次揮手
腦殘式網路程式設計入門(二):我們在讀寫Socket時,究竟在讀寫什麼?
腦殘式網路程式設計入門(三):HTTP協議必知必會的一些知識
腦殘式網路程式設計入門(四):快速理解HTTP/2的伺服器推送(Server Push)
腦殘式網路程式設計入門(五):每天都在用的Ping命令,它到底是什麼?
腦殘式網路程式設計入門(六):什麼是公網IP和內網IP?NAT轉換又是什麼鬼?
以網遊服務端的網路接入層設計為例,理解實時通訊的技術挑戰
邁向高階:優秀Android程式設計師必知必會的網路基礎
全面瞭解移動端DNS域名劫持等雜症:技術原理、問題根源、解決方案等
美圖App的移動端DNS優化實踐:HTTPS請求耗時減小近半
Android程式設計師必知必會的網路通訊傳輸層協議——UDP和TCP
IM開發者的零基礎通訊技術入門(一):通訊交換技術的百年發展史(上)
IM開發者的零基礎通訊技術入門(二):通訊交換技術的百年發展史(下)
IM開發者的零基礎通訊技術入門(三):國人通訊方式的百年變遷
IM開發者的零基礎通訊技術入門(四):手機的演進,史上最全移動終端發展史
IM開發者的零基礎通訊技術入門(五):1G到5G,30年行動通訊技術演進史
IM開發者的零基礎通訊技術入門(六):移動終端的接頭人——“基站”技術
IM開發者的零基礎通訊技術入門(七):移動終端的千里馬——“電磁波”
IM開發者的零基礎通訊技術入門(八):零基礎,史上最強“天線”原理掃盲
IM開發者的零基礎通訊技術入門(九):無線通訊網路的中樞——“核心網”
IM開發者的零基礎通訊技術入門(十):零基礎,史上最強5G技術掃盲
IM開發者的零基礎通訊技術入門(十一):為什麼WiFi訊號差?一文即懂!
IM開發者的零基礎通訊技術入門(十二):上網路卡頓?網路掉線?一文即懂!
IM開發者的零基礎通訊技術入門(十三):為什麼手機訊號差?一文即懂!
IM開發者的零基礎通訊技術入門(十四):高鐵上無線上網有多難?一文即懂!
IM開發者的零基礎通訊技術入門(十五):理解定位技術,一篇就夠
百度APP移動端網路深度優化實踐分享(一):DNS優化篇
百度APP移動端網路深度優化實踐分享(二):網路連線優化篇
百度APP移動端網路深度優化實踐分享(三):移動端弱網優化篇
技術大牛陳碩的分享:由淺入深,網路程式設計學習經驗乾貨總結
可能會搞砸你的面試:你知道一個TCP連線上能發起多少個HTTP請求嗎?
>> 更多同類文章 ……

(本文同步釋出於:www.52im.net/thread-2680…


相關文章