1、什么是Keep-Alive模式?
我們知道HTTP協議采用“請求-應答”模式,
當使用普通模式,即非KeepAlive模式時,每個請求/應答客戶和服務器都要新建一個連接,完成 之后立即斷開連接(HTTP協議為無連接的協議);
當使用Keep-Alive模式(又稱持久連接、連接重用)時,Keep-Alive功能使客戶端到服 務器端的連接持續有效,
當出現對服務器的后繼請求時,Keep-Alive功能避免了建立或者重新建立連接。
http 1.0中默認是關閉的,需要在http頭加入"Connection: Keep-Alive",才能啟用Keep-Alive;
http 1.1中默認啟用Keep-Alive,如果加入"Connection: close ",才關閉。
目前大部分瀏覽器都是用http1.1協議,也就是說默認都會發起Keep-Alive的連接請求了,所以是否能完成一個完整的Keep- Alive連接就看服務器設置情況。
2、啟用Keep-Alive的優點
從上面的分析來看,啟用Keep-Alive模式肯定更高效,性能更高。因為避免了建立/釋放連接的開銷;
注意:單用戶客戶端與任何服務器或代理之間的連接數不應該超過2個。
一個代理與其它服務器或代碼之間應該使用不超過2 * N的活躍並發連接。
這是為了提高HTTP響應時間,避免擁塞(冗余的連接並不能代碼執行性能的提升)。
3、回到我們的問題(即如何判斷消息內容/長度的大小?)
Keep-Alive模式,客戶端如何判斷請求所得到的響應數據已經接收完成(或者說如何知道服務器已經發生完了數據)?
我們已經知道 了,Keep-Alive模式發送完數據HTTP服務器不會自動斷開連接,所有不能再使用返回EOF(-1)來判斷;
(當然你一定要這樣使用也沒有辦法,可 以想象那效率是何等的低)!下面我介紹兩種來判斷方法。
3.1、使用消息首部字段Conent-Length
故名思意,Conent-Length表示實體內容長度,客戶端(服務器)可以根據這個值來判斷數據是否接收完成。
但是如果消息中沒有Conent-Length,那該如何來判斷呢?又在什么情況下會沒有Conent-Length呢?請繼續往下看……
3.2、使用消息首部字段Transfer-Encoding
當客戶端向服務器請求一個靜態頁面或者一張圖片時,服務器可以很清楚的知道內容大小,
然后通過Content-length消息首部字段告訴客戶端 需要接收多少數據。
但是如果是動態頁面等時,服務器是不可能預先知道內容大小,這時就可以使用Transfer-Encoding:chunk模式來傳輸 數據了。
即如果要一邊產生數據,一邊發給客戶端,服務器就需要使用"Transfer-Encoding: chunked"這樣的方式來代替Content-Length。
chunk編碼將數據分成一塊一塊的發生。
Chunked編碼將使用若干個Chunk串連而成,由一個標明長度為0 的chunk標示結束。
每個Chunk分為頭部和正文兩部分,頭部內容指定正文的字符總數(十六進制的數字 )和數量單位(一般不寫),
正文部分就是指定長度的實際內容,兩部分之間用回車換行(CRLF) 隔開。
在最后一個長度為0的Chunk中的內容是稱為footer的內容,是一些附加的Header信息(通常可以直接忽略)。
Chunk編碼的格式如下:
復制代碼
代碼如下:
Chunked-Body = *<strong>chunk </strong>
"0" CRLF
footer
CRLF
chunk = chunk-size [ chunk-ext ] CRLF
chunk-data CRLF</p><p>hex-no-zero = <HEX excluding "0"></p><p>chunk-size = hex-no-zero *HEX
chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-value ] )
chunk-ext-name = token
chunk-ext-val = token | quoted-string
chunk-data = chunk-size(OCTET)</p><p>footer = *entity-header
即Chunk編碼由四部分組成: 1、<strong>0至多個chunk塊</strong> ,2、<strong>"0" CRLF </strong>,3、<strong>footer </strong>,4、<strong>CRLF</strong> <strong>.</strong> 而每個chunk塊由:chunk-size、chunk-ext(可選)、CRLF、chunk-data、CRLF組成。
4、消息長度的總結
其實,上面2中方法都可以歸納為是如何判斷http消息的大小、消息的數量。
RFC 2616 對 消息的長度總結如下:一個消息的transfer-length(傳輸長度)是指消息中的message-body(消息體)的長度。
當應用了 transfer-coding(傳輸編碼),每個消息中的message-body(消息體)的長度(transfer-length)由以下幾種情況 決定(優先級由高到低):
任何不含有消息體的消息(如1XXX、204、304等響應消息和任何頭(HEAD,首部)請求的響應消息),總是由一個空行(CLRF)結束。
如果出現了Transfer-Encoding頭字段 並且值為非“identity”,那么transfer-length由“chunked” 傳輸編碼定義,除非消息由於關閉連接而終止。
如果出現了Content-Length頭字段,它的值表示entity-length(實體長度)和transfer-length(傳輸長 度)。如果這兩個長度的大小不一樣(i.e.設置了Transfer-Encoding頭字段),那么將不能發送Content-Length頭字段。並 且如果同時收到了Transfer-Encoding字段和Content-Length頭字段,那么必須忽略Content-Length字段。
如果消息使用媒體類型“multipart/byteranges”,並且transfer-length 沒有另外指定,那么這種自定界(self-delimiting)媒體類型定義transfer-length 。除非發送者知道接收者能夠解析該類型,否則不能使用該類型。
由服務器關閉連接確定消息長度。(注意:關閉連接不能用於確定請求消息的結束,因為服務器不能再發響應消息給客戶端了。)
為了兼容HTTP/1.0應用程序,HTTP/1.1的請求消息體中必須包含一個合法的Content-Length頭字段,除非知道服務器兼容 HTTP/1.1。一個請求包含消息體,並且Content-Length字段沒有給定,如果不能判斷消息的長度,服務器應該用用400 (bad request) 來響應;或者服務器堅持希望收到一個合法的Content-Length字段,用 411 (length required)來響應。
所有HTTP/1.1的接收者應用程序必須接受“chunked” transfer-coding (傳輸編碼),因此當不能事先知道消息的長度,允許使用這種機制來傳輸消息。消息不應該夠同時包含 Content-Length頭字段和non-identity transfer-coding。如果一個消息同時包含non-identity transfer-coding和Content-Length ,必須忽略Content-Length 。