HTTP概述
HTTP協議用于約定服務端(如Web服務器Tomcat、IIS)和客戶端(如瀏覽器、APP)通信的消息格式和響應方式。了解HTTP協議內容有助于優化Http請求,如斷點下載、多線程下載、防盜鏈等功能的實現。HTTP協議是建立在TCP協議之上的,理論上只要有一個Socket就能夠實現Http消息的請求,實現比如HttpClient、UrlConnection的請求操作。只要有一個SocketServer就能夠實現Http消息的響應,實現比如Tomcat、IIS等Web服務器的功能,比如在手機上部署網站,用戶可以在瀏覽器端訪問同一網絡下的手機部署的站點。
HTTP請求協議詳解
HTTP1.1的請求協議報文結構如下圖,大體上可以分為三塊,即請求行、頭部、消息主體。
請求行
請求行包含HTTP請求方法、請求的URL、HTTP協議版本三個內容,它們之間以空格間隔,并以回車+換行結束。
HTTP請求方法有下面幾種,常用的有GET、POST請求。
- OPTIONS
- GET
- HEAD
- POST
- DELETE
- TRACE
- CONNECT
請求頭部
頭部可以分成三個部分,為常用頭域、請求頭域、實體頭域。其中常用頭域和實體頭域部分內容在響應協議部分也有相同的定義。
常用頭域
常用頭域名稱 | 作用描述 |
---|---|
Cache-Control | 緩存控制 |
Connection | HTTP 1.1默認是支持長連接的(Keep-Alive),如果不希望支持長連接則需要在此域中寫入close |
Date | 表明消息產生的日期和時間 |
Pragma | |
Trailer | |
Transfer-Encoding | 告知接收端為了保證報文的可靠傳輸,對報文采用了什么編碼方式 |
Upgrade | 給出了發送端可能想要”升級”使用的新版本或協議 |
Via | 顯示了報文經過的中間節點(代理、網關) |
Warning |
請求頭域
請求頭域名稱 | 作用描述 |
---|---|
Accept | 指明請求端可以接受處理的媒體類型 |
Accept-Charset | 指明請求端可以接受的字符集 |
Accept-Encoding | 指明請求端可以接受的編碼格式 |
Authorization | 授權 |
Expect | 允許客戶端列出某請求所要求的服務器行為 |
From | 提供了客戶端用戶的E-mail地址 |
Host | 指明請求端的網絡主機和端口號 |
If-Match | 服務端在響應頭部里面返回ETag信息,客戶端請求時在頭部添加If-Match(值為響應的ETag),服務端接收后判斷ETag是否相同,若相同則處理請求,否則不處理請求。 |
If-Modified-Since | 客戶端在請求某一資源文件時,在頭部加上If-Modified-Since(值為該資源文件的最后修改時間),服務端接收后將客戶端上報的修改時間與服務器存儲的文件的最后修改時間做對比,如果相同,說明資源文件沒有更新,返回304狀態碼,告訴客戶端使用原來的緩存文件。否則返回資源內容。 |
If-None-Match | 服務端在響應頭部里面返回ETag信息,客戶端請求時在頭部添加If-None-Match(值為響應的ETag),服務端接收后判斷ETag是否相同,若相同,說明資源沒有更新,返回304狀態碼,告訴客戶端使用原來的緩存文件。否則返回資源內容。 |
If-Range | 該頭域與Range頭域一起使用,服務端在響應頭部里面返回ETag信息,客戶端請求時在頭部添加If-Range(值為響應的ETag),服務端接收后判斷ETag是否相同,若相同,則返回狀態碼206,返回內容為Range指定的字節范圍。若不相同,則返回狀態碼200,返回內容為整個實體。 |
If-Unmodified-Since | 客戶端在請求某一資源文件時,在頭部加上If-Modified-Since(值為該資源文件的最后修改時間),端接收后將客戶端上報的修改時間與服務器存儲的文件的最后修改時間做對比,如果相同,則返回資源內容,如果不相同則返回狀態碼412。 |
Max-Forwards | 配合TRACE、OPTIONS方法使用,限制在通往服務器的路徑上的代理或網關的數量。 |
Proxy-Authorization | 代理授權 |
Range | 表示客戶端向服務端請求指定范圍的字節數量:Range:bytes=0-500表示請求第1個到第501個的字節數量。Range:bytes=100-表示請求第101到文件倒數第一個字節的字節數量。Range:bytes=-500表示請求最后500個字節的數量。Range可以同時指定多組(Range:bytes=500-600,601-999)。并不是所有的服務端都支持字節范圍請求的,如果支持字節范圍請求,服務端會返回狀態碼206,若不支持則會返回200,客戶端需要根據狀態碼來判斷服務端是否支持字節范圍操作。此域可用于斷點下載,即在斷點處請求后面的內容,也可用于多線程下載同一個文件,每個線程負責一個文件的一部分下載工作,多個線程協同完成整個文件的下載。 |
Referer | 用于指定客戶端請求的來源,是從搜索引擎過來的?還是從其它網站鏈接過來的?服務器根據此域,有時可以用做防盜鏈處理,不在指定范圍內的來源,統統拒絕。 |
TE | 指明客戶端可以接受哪些傳輸編碼。 |
實體頭域
實體頭域名稱 | 作用描述 |
---|---|
Allow | 指明被請求的資源所支持的方法,如GET、HEAD、PUT |
Content-Encoding | 指明實體內容所采用的編碼方式 |
Content-Language | 指明實體內容使用的語言 |
Content-Length | 指明請求實體的字節數量 |
Content-Location | 可以用來為實體提供對應資源的位置 |
Content-MD5 | 指定實體內容的MD5,用于內容的完整性校驗(base64的128位MD5) |
Content-Range | |
Content-Type | 指定實體的媒體類型 |
Expires | 指明實體的過期時間 |
Last-Modified | 指明實體最后被修改的時間 |
HTTP響應協議詳解
HTTP1.1的響應協議報文結構如下圖,大體上可以分為三塊,即狀態行、頭部、消息主體。
狀態行
狀態行包含HTTP協議版本、狀態碼、原因短語三個內容,它們之間以空格間隔,并以回車+換行結束。
狀態碼由三位數字組成,第一位數字定義了響應類型,主要有如下五種類型的狀態碼
狀態碼類型 | 作用描述 |
---|---|
1xx | 報告(請求被接收,繼續處理) |
2xx | 成功(請求被成功的接收并處理) |
3xx | 重發 |
4xx | 客戶端出錯(客戶端錯誤的協議格式和不能處理的請求) |
5xx | 服務器出錯(服務器無法完成有效的請求處理) |
狀態碼和對應的原因短語詳細描述
狀態碼 | 原因短語 | 中文描述 |
---|---|---|
100 | Continue | 繼續 |
101 | Switching Protocols | 切換協議 |
200 | OK | 成功 |
201 | Created | 已創建 |
202 | Accepted | 接受 |
203 | Non-Authoritative information | 非權威信息 |
204 | No Content | 無內容 |
205 | Reset Content | 重置內容 |
206 | Partial Content | 部分內容 |
300 | Multiple Choices | 多個選擇 |
301 | Moved Permanently | 永久移動 |
302 | Found | 發現 |
303 | See Other | 見其它 |
304 | Not Modified | 沒有改變 |
305 | Use Proxy | 使用代理 |
307 | Temporary Redirect | 臨時重發 |
400 | Bad Request | 壞請求 |
401 | Unauthorized | 未授權的 |
402 | Payment Required | 必需的支付 |
403 | Forbidden | 禁用 |
404 | Not Found | 沒有找到 |
405 | Method Not Allowed | 方法不被允許 |
406 | Not Acceptable | 不可接受的 |
407 | Proxy Authentication Required | 需要代理驗證 |
408 | Request Timeout | 請求超時 |
409 | Confilict | 沖突 |
410 | Gone | 不存在 |
411 | Length Required | 長度必需 |
412 | Precondition Failed | 先決條件失敗 |
413 | Request Entity Too Large | 請求實體太大 |
414 | Request-URI Too Long | 請求URI太長 |
415 | Unsupported Media Type | 不支持的媒體類型 |
416 | Requested Range Not Satisfiable | 請求范圍不被滿足 |
417 | Expectation Failed | 期望失敗 |
500 | Internal Server Error | 內部服務器錯誤 |
501 | Not Implemented | 服務端沒有實現 |
502 | Bad Gateway | 壞網關 |
503 | Service Unavailable | 服務不能獲得 |
504 | Gateway Timeout | 網關超時 |
505 | HTTP Version Not Supported | HTTP協議版本不支持 |
響應頭域
響應頭域名稱 | 作用描述 |
---|---|
Accept-Ranges | 服務器向客戶端指明服務器對范圍請求的接受度 |
Age | 從原始服務器到代理緩存形成的估算時間(以秒計,非負) |
ETag | 實體標簽 |
Location | 指定重定向的URI |
Proxy-Autenticate | 它指出認證方案和可應用到代理的該URL上的參數 |
Retry-After | 如果實體暫時不可取,通知客戶端在指定時間之后再次嘗試 |
Server | 指明服務器用于處理請求的軟件信息 |
Vary | 告訴下游代理是使用緩存響應還是從原始服務器請求 |
WWW-Authenticate | 表明客戶端請求實體應該使用的授權方案 |
參考資料
HTTP 2.0 協議詳解
一、HTTP 2.0:改進傳輸性能
HTTP 2.0 的主要目標是改進傳輸性能,實現低延遲和高吞吐量。從另一方面看,HTTP 的高層協議語義并不會因為這次版本升級而受影響。所有HTTP 首部、值,以及它們的使用場景都不會變。
現有的任何網站和應用,無需做任何修改都可以在HTTP 2.0 上跑起來。不用為了利用HTTP 2.0 的好處而修改標記。HTTP 服務器必須運行HTTP 2.0 協議,但大部分用戶都不會因此而受到影響。
二、HTTP2.0歷史及其與SPDY的淵源
SPDY 是谷歌開發的一個實驗性協議,于2009 年年中發布,主要目標是通過解決HTTP 1.1 中廣為人知的一些性能限制,來減少網頁的加載延遲
SPDY協議設定的目標
頁面加載時間(PLT,Page ? Load Time)降低 50%;
無需網站作者修改任何內容;
把部署復雜性降至最低,無需變更網絡基礎設施;
與開源社區合作開發這個新協議;
-
收集真實性能數據,驗證這個實驗性協議是否有效。
Alt text
注:為了達到降低50% 頁面加載時間的目標,SPDY 引入了一個新的二進制分幀數據層,以實現多向請求和響應、優先次序、最小化及消除不必要的網絡延遲,目的是更有效地利用底層TCP 連接;
HTTP-WG(HTTP Working Group)在2012 年初把HTTP 2.0提到了議事日程,吸取SPDY 的經驗教訓,并在此基礎上制定官方標準
三、HTTP2.0深入探究
HTTP/2.0 應該滿足如下條件:
- 相對于使用TCP 的HTTP 1.1,? 用戶在大多數情況下的感知延遲要有實質上、可度量的改進;
- 解決 HTTP 中的“隊首阻塞”問題;
- 并行操作無需與服務器建立多個連接,從而改進 TCP 的利用率,特別是擁塞控制方面;
- 保持 HTTP 1.1 的語義,利用現有文檔,包括(但不限于)HTTP 方法、狀態碼、URI,以及首部字段;
- 明確規定 HTTP 2.0 如何與 HTTP 1.x 互操作,特別是在中間介質上;
- 明確指出所有新的可擴展機制以及適當的擴展策略。
HTTP 2.0 致力于突破上一代標準眾所周知的性能限制,但它也是對之前1.x 標準的擴展,而非替代。之所以要遞增一個大版本到2.0,主要是因為它改變了客戶端與服務器之間交換數據的方式,HTTP 2.0 增加了新的二進制分幀數據層
四、HTTP2.0設計和技術目標
HTTP/2.0 通過支持首部字段壓縮和在同一連接上發送多個并發消息,讓應用更有效地利用網絡資源,減少感知的延遲時間。而且,它還支持服務器到客戶端的主動推送機制。
-
二進制分幀層
- HTTP 2.0 二進制分幀層,封裝HTTP 消息并在客戶端與服務器之間傳輸
Alt textHTTP2.0 將所有傳輸的信息分割為更小的消息和幀,并對它們采用二進制格式的編碼。
注:HTTPS 是二進制分幀的另一個典型示例:所有HTTP 消息都以透明的方式為我們編碼和解碼,不必對應用進行任何修改。HTTP2.0工作原理有點類似
-
流、消息和幀
- 流:流是連接中的一個虛擬信道,可以承載雙向的消息;每個流都有一個唯一的整數標識符(1、2…N);
- 消息:是指邏輯上的 HTTP 消息,比如請求、響應等,由一或多個幀組成。
- 幀:HTTP 2.0 通信的最小單位,每個幀包含幀首部,至少也會標識出當前幀所屬的流,承載著特定類型的數據,如 HTTP 首部、負荷,等等
Alt text- HTTP 2.0 的所有幀都采用二進制編碼,所有首部數據都會被壓縮。
- 所有通信都在一個 TCP 連接上完成。
- HTTP 2.0 把HTTP協議通信的基本單位縮小為一個一個的幀,這些幀對應著邏輯流中的消息。相應地,很多流可以并行地在同一個TCP 連接上交換消息
-
多向請求與響應
-
HTTP 2.0 中新的二進制分幀層突破了這些限制,實現了多向請求和響應:客戶端和服務器可以把HTTP 消息分解為互不依賴的幀,然后亂序發送,最后再在另一端把它們重新組合起來
Alt text 圖中包含了同一個連接上多個傳輸中的數據流:客戶端正在向服務器傳輸一個DATA 幀(stream 5),與此同時,服務器正向客戶端亂序發送stream 1 和stream 3的一系列幀。此時,一個連接上有3 個請求/ 響應并行交換!
把HTTP 消息分解為獨立的幀,交錯發送,然后在另一端重新組裝是HTTP 2.0 最重要的一項增強。這個機制會在整個Web 技術棧中引發一系列連鎖反應,從而帶來巨大的性能提升。
* 可以并行交錯地發送請求,請求之間互不影響; * 可以并行交錯地發送響應,響應之間互不干擾; * 只使用一個連接即可并行發送多個請求和響應; * 消除不必要的延遲,從而減少頁面加載的時間; * 不必再為繞過 HTTP 1.x 限制而多做很多工作;
- HTTP 2.0 的二進制分幀機制解決了HTTP 1.x 中存在的隊首阻塞問題,也消除了并行處理和發送請求及響應時對多個連接的依賴。
-
-
請求優先級
- 把HTTP 消息分解為很多獨立的幀之后,就可以通過優化這些幀的交錯和傳輸順序,每個流都可以帶有一個31 比特的優先值:0 表示最高優先級;2的31次方-1 表示最低優先級。
- 服務器可以根據流的優先級,控制資源分配(CPU、內存、帶寬),而在響應數據準備好之后,優先將最高優先級的幀發送給客戶端。
- HTTP 2.0 一舉解決了所有這些低效的問題:瀏覽器可以在發現資源時立即分派請求,指定每個流的優先級,讓服務器決定最優的響應次序。這樣請求就不必排隊了,既節省了時間,也最大限度地利用了每個連接。
-
每個來源一個連接
-
有了新的分幀機制后,HTTP 2.0 不再依賴多個TCP 連接去實現多流并行了。每個數據流都拆分成很多幀,而這些幀可以交錯,還可以分別優先級。HTTP 2.0 連接都是持久化的,而且客戶端與服務器之間也只需要一個連接即可。
- 實驗表明,客戶端使用更少的連接肯定可以降低延遲時間。HTTP 2.0 發送的總分組數量比HTTP 差不多要少40%。
- 大多數HTTP 連接的時間都很短,而且是突發性的,但TCP 只在長時間連接傳輸大塊數據時效率才最高。HTTP 2.0 通過讓所有數據流共用同一個連接,可以更有效地使用TCP 連接。
-
-
流量控制
-
HTTP 2.0 為數據流和連接的流量控制提供了一個簡單的機制:
- 流量控制基于每一跳進行,而非端到端的控制;
- 流量控制基于窗口更新幀進行,即接收方廣播自己準備接收某個數據流的多少字節,以及對整個連接要接收多少字節;
- 流量控制窗口大小通過 WINDOW_UPDATE 幀更新,這個字段指定了流 ID 和窗口大小遞增值;
- 流量控制有方向性,即接收方可能根據自己的情況為每個流乃至整個連接設置任意窗口大小;
- 流量控制可以由接收方禁用,包括針對個別的流和針對整個連接。
-
-
服務器推送
-
HTTP 2.0 新增的一個強大的新功能,就是服務器可以對一個客戶端請求發送多個響應。服務器向客戶端推送資源無需客戶端明確地請求。
Alt text HTTP 2.0 連接后,客戶端與服務器交換SETTINGS 幀,借此可以限定雙向并發的流的最大數量。因此,客戶端可以限定推送流的數量,或者通過把這個值設置為0 而完全禁用服務器推送。
所有推送的資源都遵守同源策略。換句話說,服務器不能隨便將第三方資源推送給客戶端,而必須是經過雙方確認才行。
PUSH_PROMISE:所有服務器推送流都由PUSH_PROMISE 發端,服務器向客戶端發出的有意推送所述資源的信號。客戶端接收到PUSH_PROMISE 幀之后,可以視自身需求選擇拒絕這個流
-
幾點限制:
- 服務器必須遵循請求- 響應的循環,只能借著對請求的響應推送資源
- PUSH_PROMISE 幀必須在返回響應之前發送,以免客戶端出現競態條件。
-
-
首部壓縮(HPACK壓縮算法,一邊用index mapping table壓縮,一邊編碼,這個table由靜態表和動態表組成)
http2.0會壓縮首部元數據:在客戶端和服務器端使用“首部表”來跟蹤和存儲之前發送的鍵值對,對于相同的數據,不再通過每次請求和響應發送;“首部表”在http2.0的連接存續期內始終存在,由客戶端和服務器共同漸進地更新;每個新的首部鍵值對要么追加到當前表的末尾,要么替換表中之前的值。
-
http2.0首部差異化傳輸
Alt text- 請求與響應首部的定義在HTTP2.0中基本沒有改變,只是所有首部鍵必須全部小寫,而且請求行要獨立為 :method、:scheme、:host、:path這些鍵值對。
-
有效的HTTP2.0升級與發現
-
大多數現代瀏覽器都內置有高效的后臺升級機制,支持HTTP2.0的客戶端在發起新請求之前,必須能發現服務器及所有中間設備是否支持HTTP2.0協議。有三種可能的情況:
- 通過TLS和ALPN發起新的HTTPS連接;
- 根據之前的信息發起新的HTTP連接;
- 沒有之前的信息而發起新的HTTP連接。
HTTPS 協商過程中有一個環節會使用ALPN(應用層協議協商)。減少網絡延遲是HTTP 2.0 的關鍵條件,因此在建立HTTPS 連接時一定會用到ALPN協商。
通過常規非加密信道建立HTTP2.0連接需要多做一點工作。因為HTTP1.0和HTTP2.0都使用同一個端口(80),有沒有服務器是否支持HTTP2.0的其他任何信息,此時客戶端只能使用HTTP Upgrade機制通過協調確定適當的協議:
Upgrade: HTTP/2.0 ? HTTP2-Settings: (SETTINGS payload) ? HTTP/1.1 200 OK ? HTTP/1.1 101 Switching Protocols ? ...
? 發起帶有HTTP 2.0 Upgrade 首部的HTTP 1.1 請求 ? HTTP/2.0 SETTINGS 凈荷的Base64 URL 編碼 ? 服務器拒絕升級,通過HTTP 1.1 返回響應 ? 服務器接受HTTP 2.0 升級,切換到新分幀
-
HTTP2.0二進制分幀簡介
建立HTTP2.0連接后,客戶端與服務器會通過交換幀來通信,幀是基于這個新協議通信的最小單位。所有幀都共享一個8字節的首部,其中包含幀的長度、類型、標志,還有一個保留位和一個31位的流標識符。
-
發起新流
- 在發送應用數據之前,必須創建一個新流并隨之發送相應的元數據,比如流優先級、HTTP 首部等;
- 客戶端通過發送HEADERS幀來發起新流;
- 服務器通過發送 PUSH_PROMISE 幀來發起推送流。
Alt text -
發送應用數據
- 創建新流并發送HTTP 首部之后,接下來就是利用DATA 幀。應用數據可以分為多個DATA 幀,最后一幀要翻轉幀首部的END_STREAM 字段
Alt text- HTTP 2.0 標準要求DATA 幀不能超過2的14次方-1(16383)字節。長度超過這個閥值的數據,就得分幀發送。
-
HTTP2.0幀數據流分析
- HTTP2.0在共享的連接上同時發送請求和響應
Alt text- 3 個流的 ID 都是奇數,說明都是客戶端發起的
- 服務器發送的 stream 1 包含多個 DATA 幀,這是對客戶端之前請求的響應數據
- 服務器在交錯發送 stream 1 的 DATA 幀和 stream 3 的 HEADERS 幀,這就是響應的多路復用!
- 客戶端正在發送 stream 5 的 DATA 幀,表明 HEADERS 幀之前已經發送過了。
針對HTTP2.0的優化建議
-
去掉對1.x的優化
- 每個來源使用一個連接,HTTP 2.0 通過將一個TCP 連接的吞吐量最大化來提升性能。
- 去掉不必要的文件合并和圖片拼接:HTTP 2.0,很多小資源都可以并行發送
- 利用服務器推送:之前針對HTTP 1.x 而嵌入的大多數資源,都可以而且應該通過服務器推送來交付。
-
雙協議應用策略
- 相同的應用代碼,雙協議部署
- 分離應用代碼,雙協議部署
- 動態HTTP 1.x和HTTP 2.0優化:某些自動化的Web 優化框架在響應請求時動態重寫交付的應用代碼(包括連接、拼合、分區,等等)
- 單協議部署
-
1.x與2.0的相互轉換
Alt text -
評估服務器質量與性能
- HTTP 2.0 服務器必須理解流優先級;
- HTTP 2.0 服務器必須根據優先級處理響應和交付資源;
- HTTP 2.0 服務器必須支持服務器推送;
- HTTP 2.0 服務器應該提供不同推送策略的實現。
-
2.0與TLS
-
兩種可能出現ALPN 協商和TLS 終止的情況
- TLS 連接可能會在 HTTP 2.0 服務器上終止;
- TLS 連接可能會在上游(如負載均衡器)上終止。
第一種情況要求HTTP 2.0 服務器能夠處理TLS;
第二種情況建立一條加密信道,直接將非加密的HTTP 2.0 流發送到服務器
Alt text -
-
負載均衡器、代理及應用服務器
- 要在TLS 之上實現HTTP 2.0通信,終端服務器必須支持 ALPN;
- 盡可能在接近用戶的地方終止 TLS;
- 如果無法支持 ALPN,那么選擇 TCP 負載均衡模式;
- 如果無法支持 ALPN 且 TCP 負載均衡也做不到,那么就退而求其次,在非加密信道上使用HTTP 的Upgrade 流;
TCP/IP
TCP/IP是個協議組,可分為三個層次:網絡層、傳輸層和應用層。
在網絡層有IP協議、ICMP協議、ARP協議、RARP協議和BOOTP協議。
在傳輸層中有TCP協議與UDP協議。
在應用層有:TCP包括FTP、HTTP、TELNET、SMTP等協議
UDP包括DNS、TFTP等協議
短連接
連接->傳輸數據->關閉連接
HTTP是無狀態的,瀏覽器和服務器每進行一次HTTP操作,就建立一次連接,但任務結束就中斷連接。
也可以這樣說:短連接是指SOCKET連接后發送后接收完數據后馬上斷開連接。
長連接
連接->傳輸數據->保持連接 -> 傳輸數據-> 。。。 ->關閉連接。
長連接指建立SOCKET連接后不管是否使用都保持連接,但安全性較差。
http的長連接
HTTP也可以建立長連接的,使用Connection:keep-alive,HTTP 1.1默認進行持久連接。HTTP1.1和HTTP1.0相比較而言,最大的區別就是增加了持久連接支持(貌似最新的 http1.0 可以顯示的指定 keep-alive),但還是無狀態的,或者說是不可以信任的。
什么時候用長連接,短連接?
長連接多用于操作頻繁,點對點的通訊,而且連接數不能太多情況,。每個TCP連接都需要三步握手,這需要時間,如果每個操作都是先連接,再操作的話那么處理速度會降低很多,所以每個操作完后都不斷開,次處理時直接發送數據包就OK了,不用建立TCP連接。例如:數據庫的連接用長連接, 如果用短連接頻繁的通信會造成socket錯誤,而且頻繁的socket 創建也是對資源的浪費。
而像WEB網站的http服務一般都用短鏈接,因為長連接對于服務端來說會耗費一定的資源,而像WEB網站這么頻繁的成千上萬甚至上億客戶端的連接用短連接會更省一些資源,如果用長連接,而且同時有成千上萬的用戶,如果每個用戶都占用一個連接的話,那可想而知吧。所以并發量大,但每個用戶無需頻繁操作情況下需用短連好。
總之,長連接和短連接的選擇要視情況而定。
發送接收方式
1、異步
報文發送和接收是分開的,相互獨立的,互不影響。這種方式又分兩種情況:
(1)異步雙工:接收和發送在同一個程序中,由兩個不同的子進程分別負責發送和接收
(2)異步單工:接收和發送是用兩個不同的程序來完成。
2、同步
報文發送和接收是同步進行,既報文發送后等待接收返回報文。 同步方式一般需要考慮超時問題,即報文發出去后不能無限等待,需要設定超時時間,超過該時間發送方不再等待讀返回報文,直接通知超時返回。
在長連接中一般是沒有條件能夠判斷讀寫什么時候結束,所以必須要加長度報文頭。讀函數先是讀取報文頭的長度,再根據這個長度去讀相應長度的報文。
Socket是什么
Socket是應用層與TCP/IP協議族通信的中間軟件抽象層,它是一組接口。在設計模式中,Socket其實就是一個門面模式,它把復雜的TCP/IP協議族隱藏在Socket接口后面,對用戶來說,一組簡單的接口就是全部,讓Socket去組織數據,以符合指定的協議。
[圖片上傳失敗...(image-bfb4aa-1527588784406)]
通信過程:
[圖片上傳失敗...(image-90d03b-1527588784405)]
主機 A 的應用程序要能和主機 B 的應用程序通信,必須通過 Socket 建立連接,而建立 Socket 連接必須需要底層 TCP/IP 協議來建立 TCP 連接。建立 TCP 連接需要底層 IP 協議來尋址網絡中的主機。我們知道網絡層使用的 IP 協議可以幫助我們根據 IP 地址來找到目標主機,但是一臺主機上可能運行著多個應用程序,如何才能與指定的應用程序通信就要通過 TCP 或 UPD 的地址也就是端口號來指定。這樣就可以通過一個 Socket 實例唯一代表一個主機上的一個應用程序的通信鏈路了。
建立通信鏈路
當客戶端要與服務端通信,客戶端首先要創建一個 Socket 實例,操作系統將為這個 Socket 實例分配一個沒有被使用的本地端口號,并創建一個包含本地和遠程地址和端口號的套接字數據結構,這個數據結構將一直保存在系統中直到這個連接關閉。在創建 Socket 實例的構造函數正確返回之前,將要進行 TCP 的三次握手協議,TCP 握手協議完成后,Socket 實例對象將創建完成,否則將拋出 IOException 錯誤。
與之對應的服務端將創建一個 ServerSocket 實例,ServerSocket 創建比較簡單只要指定的端口號沒有被占用,一般實例創建都會成功,同時操作系統也會為 ServerSocket 實例創建一個底層數據結構,這個數據結構中包含指定監聽的端口號和包含監聽地址的通配符,通常情況下都是“*”即監聽所有地址。之后當調用 accept() 方法時,將進入阻塞狀態,等待客戶端的請求。當一個新的請求到來時,將為這個連接創建一個新的套接字數據結構,該套接字數據的信息包含的地址和端口信息正是請求源地址和端口。這個新創建的數據結構將會關聯到 ServerSocket 實例的一個未完成的連接數據結構列表中,注意這時服務端與之對應的 Socket 實例并沒有完成創建,而要等到與客戶端的三次握手完成后,這個服務端的 Socket 實例才會返回,并將這個 Socket 實例對應的數據結構從未完成列表中移到已完成列表中。所以 ServerSocket 所關聯的列表中每個數據結構,都代表與一個客戶端的建立的 TCP 連接。
備注:
Windows 下單機最大TCP連接數
調整系統參數來調整單機的最大TCP連接數,Windows 下單機的TCP連接數有多個參數共同決定:
以下都是通過修改注冊表[HKEY_LOCAL_MACHINE \System \CurrentControlSet \Services \Tcpip \Parameters]
**1.最大TCP連接數 ** TcpNumConnections
2.TCP關閉延遲時間 TCPTimedWaitDelay (30-240)s
3.最大動態端口數 MaxUserPort (Default = 5000, Max = 65534) TCP客戶端和服務器連接時,客戶端必須分配一個動態端口,默認情況下這個動態端口的分配范圍為 1024-5000 ,也就是說默認情況下,客戶端最多可以同時發起3977 Socket 連接
4.最大TCB 數量 MaxFreeTcbs
系統為每個TCP 連接分配一個TCP 控制塊(TCP control block or TCB),這個控制塊用于緩存TCP連接的一些參數,每個TCB需要分配 0.5 KB的pagepool 和 0.5KB 的Non-pagepool,也就說,每個TCP連接會占用 1KB 的系統內存。
非Server版本,MaxFreeTcbs 的默認值為1000 (64M 以上物理內存)Server 版本,這個的默認值為 2000。也就是說,默認情況下,Server 版本最多同時可以建立并保持2000個TCP 連接。
5. 最大TCB Hash table 數量 MaxHashTableSize TCB 是通過Hash table 來管理的。
這個值指明分配 pagepool 內存的數量,也就是說,如果MaxFreeTcbs = 1000 , 則 pagepool 的內存數量為 500KB那么 MaxHashTableSize 應大于 500 才行。這個數量越大,則Hash table 的冗余度就越高,每次分配和查找 TCP 連接用時就越少。這個值必須是2的冪,且最大為65536.
IBM WebSphere Voice Server 在windows server 2003 下的典型配置
MaxUserPort = 65534 (Decimal)
MaxHashTableSize = 65536 (Decimal)
MaxFreeTcbs = 16000 (Decimal)
這里我們可以看到 MaxHashTableSize 被配置為比MaxFreeTcbs 大4倍,這樣可以大大增加TCP建立的速度
短連接和長連接
短連接:每次Http請求都會建立Tcp連接,管理容易
-
長連接:只需要建立一次Tcp連接,以后Http請求重復使用同一個Tcp連接,管理難
這里寫圖片描述HTTP1.1規定了默認保持長連接(HTTP persistent connection ,也有翻譯為持久連接),數據傳輸完成了保持TCP連接不斷開(不發RST包、不四次握手),等待在同域名下繼續用這個通道傳輸數據;相反的就是短連接
如果服務器沒有告訴客戶端超時時間也沒關系,服務端可能主動發起四次握手斷開TCP連接,客戶端能夠知道該TCP連接已經無效;另外TCP還有心跳包來檢測當前連接是否還活著,方法很多,避免浪費資源。
在長連接的應用場景下,client端一般不會主動關閉它們之間的連接,Client與server之間的連接如果一直不關閉的話,會存在一個問題,隨著客戶端連接越來越多,server早晚有扛不住的時候,這時候server端需要采取一些策略,如關閉一些長時間沒有讀寫事件發生的連接,這樣可以避免一些惡意連接導致server端服務受損;如果條件再允許就可以以客戶端機器為顆粒度,限制每個客戶端的最大長連接數,這樣可以完全避免某個蛋疼的客戶端連累后端服務。
長連接和短連接的產生在于client和server采取的關閉策略,具體的應用場景采用具體的策略,沒有十全十美的選擇,只有合適的選擇
應用場景區別:
- 一般長連接(追求實時性高的場景)用于少數client-end to server-end的頻繁的通信,例如:數據庫的連接用長連接, 如果用短連接頻繁的通信會造成socket錯誤,而且頻繁的socket 創建也是對資源的浪費。
- 而像WEB網站的http服務一般都用短鏈接(追求資源易回收場景),因為長連接對于服務端來說會耗費一定的資源,而像WEB網站這么頻繁的成千上萬甚至上億客戶端的連接用短連接會更省一些資源。
短輪詢和長輪詢
和短連接和長連接有本質區別
1. 短輪詢:重復發送Http請求,查詢目標事件是否完成,優點:編寫簡單,缺點:浪費帶寬和服務器資源
2. 長輪詢:在服務端hold住Http請求(死循環或者sleep等等方式),等到目標時間發生,返回Http響應。優點:在無消息的情況下不會頻繁的請求,缺點:編寫復雜