HTTP學習筆記(一)報文和連接管理

對TCP/IP協議簇有些瞭解的同學們應該都知道,TCP/IP協議通過精簡ISO網絡7層協議(其實瞭解歷史淵源的話,TCP/IP協議本來目的並不是簡化ISO的7層協議,只是因爲ISO協議簇制定速度慢於互聯網通信技術發展的速度,TCP/IP協議已經被各大廠商私下廣泛商用化,ISO網絡通信標準才制定完成,所以,鑑於已經廣泛應用的TCP/IP協議已經成爲各大通信商的實際默認標準,ISO只能作爲理論研究標準來供研究之用)來保證我們的網絡通信的基礎架構。

自己對HTTP協議的瞭解基本停留在大學計算機網絡的瞭解程度,一直想深入瞭解點HTTP的細節,所以最近在拜讀《HTTP完全解析》這本著作,覺得堪稱HTTP解讀經典,由於全書的內容太多,一邊拜讀一邊做做筆記加深印象和理解。


1.TCP協議的貢獻

HTTP協議是TCP/IP協議簇應用層的傳輸協議,Web瀏覽器、服務器和移動客戶端應用層、服務器交互都是通過HTTP互相通信。HTTP協議是基於傳輸層可靠的數據傳輸協議TCP協議實現,而且HTTP無需操心網絡通信的細節,它把聯網的細節到交給通用、可靠的TCP/IP協議簇的應用層下面幾層協議處理。順便說下,TCP協議向HTTP協議屏蔽了數據傳輸的細節,TCP至少給HTTP協議的工作提供了一下保證:

  • 無差錯的數據傳輸;
  • 按序傳輸(數據總是會按照發送的順序到達);
  • 未分段的數據流(可以在任意時刻以任意尺寸將數據發送出去)。

2.HTTP協議的基本結構

討論HTTP協議的細節,我們離不開HTTP傳輸協議的基本數據單元,HTTP報文是HTTP應用之間發送的基本單位。HTTP報文都可以分爲兩類:請求報文(Request Message)和響應報文(Response Message)。如果大家對HTTP報文的基本結構還不是很清楚的話,轉到《Http Message結構學習總結》,我覺得這部分看我的筆記肯定還不如他的通俗易懂。

3.HTTP連接管理和HTTP優化

我們知道HTTP協議直接緊挨着TCP協議,因爲TCP爲HTTP提供了一條可靠的比特傳輸通道,從TCP連接的一端填入的字節會從另一端已原來的順序、正確地傳送出來,讓HTTP協議不用考慮傳輸的細節,可以集中盡力處理應用層的事情。那我們可以這樣理解,HTTP傳輸的性能很大程度上直接取決於底層TCP通道的性能。我們只有更好的理解了TCP的某些性能特點之後,就可以更好的理解HTTP的連接優化特性,這樣我們纔可以考慮到我們的軟件有更高的HTTP性能。下面說說TCP協議對HTTP性能的影響:

1.HTTP的時延

在 HTTP 請求的過程中會出現哪些網絡時延,並以此開始我們的TCP 性能之旅。圖 1 描繪了 HTTP 事務主要的連接、傳輸以及處理時延。
這裏寫圖片描述

與因特網傳輸請求報文,以及服務器處理請求報文都需要時間。建立 TCP 連接,以及傳輸請求和響應報文的時間相比,事務處理時間可能是很短的。除非客戶端或服務器超載,或正在處理複雜的動態資源,否則 HTTP時延就是由 TCP 網絡時延構成的。

HTTP 事務的時延有以下幾種主要原因:

  1. 客戶端首先需要根據 URI 確定 Web 服務器的 IP 地址和端口號。如果最近沒有對URI 中的主機名進行訪問,通過 DNS 解析系統將 URI 中的主機名轉換成一個 IP地址可能要花費數十秒的時間。

  2. 接下來,客戶端會向服務器發送一條 TCP 連接請求,並等待服務器回送一個請求接受應答。每條新的 TCP 連接都會有連接建立時延。這個值通常最多隻有一兩秒鐘,但如果有數百個 HTTP 事務的話,這個值會快速地疊加上去。

  3. 一旦連接建立起來了,客戶端就會通過新建立的 TCP 管道來發送 HTTP 請求。數據到達時,Web 服務器會從 TCP 連接中讀取請求報文,並對請求進行處理。因特網傳輸請求報文,以及服務器處理請求報文都需要時間。

  4. 然後,Web 服務器會回送 HTTP 響應,這也需要花費時間。

這些 TCP 網絡時延的大小取決於硬件速度、網絡和服務器的負載,請求和響應報文的尺寸,以及客戶端和服務器之間的距離。TCP 協議的技術複雜性也會對時延產生巨大的影響。

2.性能聚集區域

  • 本節其餘部分列出了一些會對 HTTP 程序員產生影響的、最常見的 TCP 相關時延,其中包括:
    1. TCP 連接建立握手;
    2. TCP 慢啓動擁塞控制;
    3. 數據聚集的 Nagle 算法;
    4. 用於捎帶確認的 TCP 延遲確認算法;
    5. TIME_WAIT 時延和端口耗盡。

下面我們主要說說TCP連接的握手時延、延時確認、TCP慢啓動。

1.TCP連接的握手延時

建立一條新的 TCP 連接時,甚至是在發送任意數據之前,TCP 軟件之間會交換一系列的 IP 分組,對連接的有關參數進行溝通(參見圖 2) 。如果連接只用來傳送少量數據,這些交換過程就會嚴重降低 HTTP 的性能。

這裏寫圖片描述

TCP 連接握手需要經過以下幾個步驟。

  1. 請求新的 TCP 連接時,客戶端要向服務器發送一個小的 TCP 分組(通常是 40 ~60 個字節) 。這個分組中設置了一個特殊的 SYN 標記,說明這是一個連接請求。
  2. 如果服務器接受了連接,就會對一些連接參數進行計算,並向客戶端回送一個TCP 分組,這個分組中的 SYN 和 ACK 標記都被置位,說明連接請求已被接受。
  3. 最後,客戶端向服務器回送一條確認信息,通知它連接已成功建立。現代的 TCP 棧都允許客戶端在這個確認分組中發送數據。

HTTP 程序員永遠不會看到這些分組——這些分組都由 TCP/IP 軟件管理,對其是不可見的。HTTP 程序員看到的只是創建 TCP 連接時存在的時延。

通常 HTTP 事務都不會交換太多數據,此時,SYN/SYN+ACK 握手會產生一個可測量的時延。TCP 連接的 ACK 分組通常都足夠大,可以承載整個 HTTP 請求報文4,而且很多 HTTP 服務器響應報文都可以放入一個 IP 分組中去(比如,響應是包含了裝飾性圖片的小型 HTML 文件,或者是對瀏覽器高速緩存請求產生的 304 Not Modified 響應) 。

最後的結果是,小的 HTTP 事務可能會在 TCP 建立上花費 50%,或更多的時間。後面的小節會討論 HTTP 是如何通過重用現存連接,來減小這種 TCP 建立時延所造成的影響的。

2.確認延時

由於因特網自身無法確保可靠的分組傳輸(因特網路由器超負荷的話,可以隨意丟棄分組) ,所以 TCP 實現了自己的確認機制來確保數據的成功傳輸。每個 TCP 段都有一個序列號和數據完整性校驗和。每個段的接收者收到完好的段時,都會向發送者回送小的確認分組。如果發送者沒有在指定的窗口時間內收到確認信息,發送者就認爲分組已被破壞或損毀,並重發數據。
由於確認報文很小,所以 TCP 允許在發往相同方向的輸出數據分組中對其進行“捎帶” 。TCP 將返回的確認信息與輸出的數據分組結合在一起,可以更有效地利用網絡。爲了增加確認報文找到同向傳輸數據分組的可能性,很多 TCP 棧都實現了一種“延遲確認”算法。延遲確認算法會在一個特定的窗口時間(通常是 100 ~ 200 毫秒)內將輸出確認存放在緩衝區中,以尋找能夠捎帶它的輸出數據分組。如果在那個時間段內沒有輸出數據分組,就將確認信息放在單獨的分組中傳送。
但是,HTTP 具有雙峯特徵的請求 - 應答行爲降低了捎帶信息的可能。當希望有相反方向回傳分組的時候,偏偏沒有那麼多。通常,延遲確認算法會引入相當大的時延。根據所使用操作系統的不同,可以調整或禁止延遲確認算法。

在對 TCP 棧的任何參數進行修改之前,一定要對自己在做什麼有清醒的認識。TCP中引入這些算法的目的是防止設計欠佳的應用程序對因特網造成破壞。對 TCP 配置進行的任意修改,都要絕對確保應用程序不會引發這些算法所要避免的問題。

2.TCP慢啓動

TCP 數據傳輸的性能還取決於 TCP 連接的使用期(age) 。TCP 連接會隨着時間進行自我“調諧” ,起初會限制連接的最大速度,如果數據成功傳輸,會隨着時間的推移提高傳輸的速度。這種調諧被稱爲 TCP 慢啓動(slow start) ,用於防止因特網的突然過載和擁塞。

TCP 慢啓動限制了一個 TCP 端點在任意時刻可以傳輸的分組數。簡單來說,每成功接收一個分組,發送端就有了發送另外兩個分組的權限。如果某個 HTTP 事務有大量數據要發送,是不能一次將所有分組都發送出去的。必須發送一個分組,等待確認;然後可以發送兩個分組,每個分組都必須被確認,這樣就可以發送四個分組了,以此類推。這種方式被稱爲“打開擁塞窗口” 。

由於存在這種擁塞控制特性,所以新連接的傳輸速度會比已經交換過一定量數據的、“已調諧”連接慢一些。由於已調諧連接要更快一些,所以 HTTP 中有一些可以重用現存連接的工具。

3.HTTP連接性能優化

針對TCP傳輸過程中的報文時延,有一些優化處理辦法的辦法來提供HTTP的連接性能:

1.並行連接

比如:我們的瀏覽器請求服務器資源的HTML頁面,HTML頁面包含很多文字和多個圖片資源,如果我們對文字和圖片都一個一個請求,頁面加載效果實在太慢。
目前主流瀏覽器的解決辦法是多個線程發起HTTP請求處理,並行的執行多個事務。

但是,並行連接並不是越多越好,並行連接可能可以提高頁面的訪問速度,但是並行連接不一定一直都是更快。可能還有很多其他的制約因素,比如:客戶端的網絡寬帶不足,在低速率的網絡環境下,一個HTTP事務可能就已經耗盡了網絡的帶寬。

而且,打開大量連接會消耗很多內存資源,從而引發性自身的性能問題。所以,目前的主流瀏覽器雖然使用了並行連接,但是他們對並行連接的總數都限制在一個較小的數字

2.持久連接

我們的客戶端(App 或者 web瀏覽器)經常打開到同一個站點的連接。比如:一個Web頁面上的大部分內嵌圖片通常都來自同一個Web站點,而且相當一部分指向其他對象的超鏈接通常都指向同一個站點。因此,初始化對某個服務器的HTTP請求的應用程序很可能會在不久的將來對那臺服務器發起更多的請求(比如:獲取圖片),這種性質叫站點本地性。

因此,HTTP/1.1(以及HTTP/1.0的各個增強版本)允許HTTP設備在事務處理結束之後將TCP連接保持在打開狀態,以便爲未來的HTTP請求重用現存的連接。在事務處理結束之後仍然保持在打開狀態的TCP連接稱爲持久連接。非持久連接會在每個事務結束後關閉。持久連接會在不同事務之間保持打開狀態,直到客戶端或者服務器決定將其關閉爲止。

重用已對目標服務器打開的空閒持久連接,就可以避開緩慢的連接建立階段。而且,已經打開的連接還可以避免慢啓動的擁塞適應階段,以便更快速地經行數據的傳輸。
關於持久連接的好處,下面引用原著的一幅圖來說明:

這裏寫圖片描述
從圖我們知道,簡單的HTTP串行連接上實現4個HTTP事務的時間線與在一條持久連接上實現同樣事務所需的時間線進行了比較。由於去掉進行連接和關閉連接的開銷,所以時間線有所縮短。

4.HTTP協議連接處理

客戶端請求時,給 HTTP請求頭加入”Connection: Keep-Alive”屬性,開啓keep-alive機制,通過使用keep-alive機制,可以減少TCP連接建立次數,也意味着可以減少TIME_WAIT狀態連接,以此提高性能和提高服務器的吞吐率(更少的TCP連接意味着更少的系統內核調用)。

下面說說下HTTP/1.0 和HTTP/1.1 下的keep-Alive的差別:

HTTP/1.0

在HTTP/1.0版本中,並沒有官方的標準來規定Keep-Alive如何工作,因此實際上它是被附加到HTTP/1.0協議上,如果客戶端瀏覽器支持Keep-Alive,那麼就在HTTP請求頭中添加一個字段 Connection: Keep-Alive,當服務器收到附帶有Connection: Keep-Alive的請求時,它也會在響應頭中添加一個同樣的字段來使用Keep-Alive。這樣一來,客戶端和服務器之間的HTTP連接就會被保持,不會斷開(超過Keep-Alive規定的時間,意外斷電等情況除外),當客戶端發送另外一個請求時,就使用這條已經建立的連接。

HTTP/1.1

在HTTP/1.1版本中,官方規定的Keep-Alive使用標準和在HTTP/1.0版本中有些不同,默認情況下所在HTTP1.1中所有連接都被保持,除非在請求頭或響應頭中指明要關閉:Connection: Close ,這也就是爲什麼Connection: Keep-Alive字段再沒有意義的原因。

1.Keep-Alive細節

說說兩點Keep-Alive模式的一些細節,讓我們對Kepp-Alive模式有更詳細的瞭解:

1. Keep-Alive模式下,客戶端如何判斷請求所得到的響應數據已經接收完成?

1.使用消息首部字段Conent-Length

故名思意,Conent-Length表示實體內容長度,客戶端(服務器)可以根據這個值來判斷數據是否接收完成。

2.使用消息首部字段Transfer-Encoding(chunk:分塊)

當客戶端向服務器請求一個靜態頁面或者一張圖片時,服務器可以很清楚的知道內容大小,然後通過Content-length消息首部字段告訴客戶端需要接收多少數據。但是如果是動態頁面等時,服務器是不可能預先知道內容大小,這時就可以使用Transfer-Encoding:chunk模式(分塊傳輸)來傳輸數據了。即如果要一邊產生數據,一邊發給客戶端,服務器就需要使用”Transfer-Encoding: chunked”這樣的方式來代替Content-Length。

2. Keep-Alive握手需要客戶端和服務器一起說的纔算嗎?

如果服務器願意爲下一條請求在連接保持在打開狀態,就在相應中包含相同的首部。如果相應中沒有Connection:Keep-Alive首部,客戶端就認爲服務器不支持keep-alive,會在發送相應報文之後關閉連接。
還有當服務器給客戶端報文包括 Connection:close首部,表示服務器告訴客戶端要關閉連接。

2.Keep-Alive選項

Keep-Alive首部只是請求將連接保持在活躍狀態。發出keep-Alive請求之後,客戶端和服務器並不一定會同意進行keep-alive會話。他們可以在任意時刻關閉空閒的Keep-Alive連接,並可隨意顯示Keep-Alive連接所處理事務的數量。

可以用Keep-Alive通用首部中制定的、由逗號分隔的選項來調節Keep-Alive的行爲。

  • 參數timeout是在Keep-Alive響應首部發送的。它估計了服務器希望將連接保持在活躍狀態的時間。這並不是一個承諾值。
  • 參數max是在Keep-Alive響應首部發送的。它估計了服務器還希望爲多少個事務保持此連接的活躍狀態。這並不是一個承諾值。
  • Keep-Alive首部還可支持任意未經處理的屬性,這些屬性主要用於診斷和調試。語法爲name [=value].

以上部分爲本人學習HTTP的報文和連接的筆記記錄,關於HTTP與Cookie機制深入理解,推薦大家轉到這篇文章《細說Cookie》。

解析HTTP、 Socket、 WebSocket等幾個概念:

Socket是什麼呢?

Socket是應用層與TCP/IP協議族通信的中間軟件抽象層,它是一組接口。就是我們經常說的套接字,在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來說,一組簡單的接口就是全部,讓Socket去組織數據,以符合指定的協議。

實際上,傳輸層的TCP是基於網絡層的IP協議的,而應用層的HTTP協議又是基於傳輸層的TCP協議的,而Socket本身不算是協議,就像上面所說,它只是提供了一個針對TCP或者UDP編程的接口。

HTTP 協議跟Socket的最大的區別

HTTP 你不是你要,服務器怎麼知道你要呢,所以,你要跟服務器說撒(request)。 HTTP是健忘鬼,剛還在問服務器伸手(request)要東西,要完馬上就完了。
Socket 客戶端和服務是雙向連接,一次建立連接,除非主動斷交,不然就雙方記住了。

舉個例子:比如我們實現一個簡單的聊天室程序:如果我們用HTTP實現,最大難題HTTP太健忘(無狀態特性),請求一次下次就不記得上次幹了啥,會話狀態很難保證;而且,我們如果HTTP是單向請求,我們客戶端需要不斷跟服務器輪詢請求,是否有人跟我聊天,說了啥,首先做不到實時聊天,而且,輪詢還需要考慮資源、流量問題,還有想要實現羣聊更是災難。以上遇到的問題,恰恰是Socket的長處。

WebSocket又是什麼?

WebSocket protocol 是HTML5一種新的協議,跟HTTP協議基本沒有關係,主要是爲了兼容現有瀏覽器的握手規範而已。Websocket是一個持久化的協議,相對於HTTP這種非持久的協議來說。

WebSocket 是基於 TCP 協議;HTTP 也是基於 TCP 協議。WebSocket連接要保持還是關閉是由你服務器應用控制說的算。WebSocket還是一個全雙工的協議,支持服務器端主動給客戶端發送消息。

HTML5爲什麼引入WebSocket協議呢?一方面爲了解決HTTP協議無狀態、無連接、單向請求不好處理,個人覺得WebSocket引入很大一部分就是爲了解決客戶端與服務端實時通信。舉個例子:如果用HTTP來實現網頁的通知消息功能,我們只能用輪詢的方式不斷向服務器發送請求來處理,然而HTTP request 的header是非常長的,裏面包含的數據可能只是一個很小的值,這樣會佔用很多的帶寬和服務器資源。而WebSocket協議建立後,服務器就可以主動向客戶端推送消息。 比如,我們以前實現在線聊天室的功能的話,會話狀態怎麼保存,怎麼知道對方有沒發送聊天信息,羣聊怎麼處理都是很難處理的問題,WebSocket協議的出現,實現在線聊天室的功能就簡化許多。PS:有一些移動端App實現的實時聊天功能就是用WebSocket協議來通信。

因此,我們從功能上可以理解,WebSocket更像是Socket功能實現,但實際跟Socket協議沒有關係。此處補充下,Socket協議支持TCP和UDP兩種方式,而WebSocket只支持TCP。

轉載請註明出處:http://blog.csdn.net/Johnnyz1234/article/details/47859563

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章