有時候,Web伺服器產生HTTP Response是無法在Header就確定訊息大小的,這時一般來說伺服器將不會提供Content-Length的頭資訊,而採用Chunked編碼動態提供body內容的長度。
進行Chunked編碼傳輸的HTTP Response會在訊息頭部設定:
Transfer-Encoding: chunked
表示Content Body將用Chunked編碼傳輸內容。
Chunked編碼使用若干個Chunk串聯而成,由一個標明長度為0的chunk標示結束。每個Chunk分為頭部和本文兩部分,頭部內容指定下一段本文的字元總數(十六進位的數字)和數量單位(一般不寫),本文部分就是指定長度的實際內容,兩部分之間用斷行符號換行(CRLF)隔開。在最後一個長度為0的Chunk中的內容是稱為footer的內容,是一些附加的Header資訊(通常可以直接忽略)。具體的Chunk編碼格式如下:
Chunked-Body = *chunk
"0" CRLF
footer
CRLF
chunk = chunk-size [ chunk-ext ] CRLF
chunk-data CRLF
hex-no-zero = <HEX excluding "0">
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)
footer = *entity-header
RFC文檔中的Chunked解碼過程如下:
length := 0
read chunk-size, chunk-ext (if any) and CRLF
while (chunk-size > 0) {
read chunk-data and CRLF
append chunk-data to entity-body
length := length + chunk-size
read chunk-size and CRLF
}
read entity-header
while (entity-header not empty) {
append entity-header to existing header fields
read entity-header
}
Content-Length := length
Remove "chunked" from Transfer-Encoding
最後提供一段PHP版本的chunked解碼代碼:
$chunk_size = (integer)hexdec(fgets( $socket_fd, 4096 ) );
while(!feof($socket_fd) && $chunk_size > 0) {
$bodyContent .= fread( $socket_fd, $chunk_size );
fread( $socket_fd, 2 ); // skip /r/n
$chunk_size = (integer)hexdec(fgets( $socket_fd, 4096 ) );
}
==========================================================
Server Push技術
伺服器推送(Server Push)的思想是由伺服器主動發送資訊,並與用戶端保持串連,直至伺服器或用戶端有一方自行中斷串連為止。
Server Push的優點在於減少了建立、銷毀串連的時間,去除了無用的頁面重新整理,缺點是佔用了大量連接埠和相關係統資源,單純的Server Push無法支援大使用者量的服務。
Server Push使用了multipart/x-mixed-replace這種MIME類型,報文範例格式如下:
Content-type:multipart/x-mixed-replace;boundary=ThisRandomString
–ThisRandomString
Content-type:text/plain
第一個對象的資料
–ThisRandomString
Content-type:text/plain
第二個(最後一個)對象的資料
–ThisRandomString–
每個資料區塊由三部分組成:一是Content-type之類的頭標,二是資料本文,三是報文邊界,每當用戶端接收到新的頭標時,原有文檔將被清除,並被新的資料區塊填充。
Apache和IIS均支援Server Push技術,筆者推薦Linux/Unix下的Apache軟體,它可以自由的增刪相應模組,以滿足較多串連狀態下的高效能需求。
===========================================
PHP-Push技術實現重新整理功能
Server push 前一段時間炒得很熱的“推”技術,不過網上大部分都是cgi的資料,偶爾看到一個法國的網站上有這麼個介紹,可惜法語看不懂,只能從他的程式中看懂點東西,現整理個例子出來大家學習一下。可以用於聊天室的資料轉送、網站上的新聞更新、等等各類更新頻繁的頁面。
以前做重新整理主要通過頁面上加標籤。
< META HTTP-EQUIV=REFRESH CONTENT="time;URL=url" > |
或者使用javascript的timeout+reload,不過這種重新整理的方法取決於時間的設定,無法連續的資料轉送且時間不好確定。採用了Server push的伺服器在客戶機做出一個請求後,和客戶機建立一個永久的串連,然後伺服器會根據客戶機的請求不斷地把資料包推向伺服器。那些你覺察不到的延遲會讓你覺得伺服器的響應和你的請求已經達到了同步的程度。
先來看一下例子再解釋。
img.php < ?php set_time_limit(0); $file = "./1.jpg"; $sep = "gIrLsKiCkAsSiTsAySsOoNaTsHiRt"; if(ereg(".*MSIE.*",$HTTP_SERVER_VARS["HTTP_USER_AGENT"])){ //如果是ie瀏覽器,直接輸出就退出,IE的不支援哦,我沒試出來過 header("Cache-Control: no-cache"); header("Pragma: no-cache"); header("Content-type: image/jpeg"); header("Content-size: " . filesize($file)); readfile($file); }else{ header("Content-Type: multipart/x-mixed-replace; boundary=$sep"); //這裡是關鍵哦,看看MIME類型說明 //你會明白 print "--$sep"; do{ print "Content-Type: image/jpeg"; readfile($file); print "--$sep"; flush(); $mt = filemtime($file); do{ sleep (1); clearstatcache(); }while($mt == filemtime($file)); }while(1);}? > |
這就是一個永久執行的頁面(網路不斷的情況下),不斷輸出圖片的內容,下面是調用的頁面。<img src=img.php>,然後開啟你的netscape或其他非ie瀏覽器查看調用頁面,好象沒什麼變化啊,別急,接著就是怎樣變動1.jpg這個圖片了,寫個另外的php頁面來測試吧,比如弄2張圖片按時間來覆蓋1.jpg(這個方法自己想,用拷貝覆蓋也行,只要1.jpg有變化)。這時你就看到調用頁面的圖片自動更新了。
使用中你會發現個問題:怎麼圖片不自動更新了。這是由於客戶機在一段時間內沒有對伺服器發生請求,也就是某一段時間內沒有新的內容向瀏覽器輸入,可能發生連線逾時現象。什麼辦法解決呢。可以在執行頁面中加個向瀏覽器發送一個空訊號,類似ftp串連方式,上面頁面中在do...while(1)間加個print("");
看完這個例子,應該知道怎麼處理不斷更新的內容了,關鍵在img.php頁面中的處理(可以是檢查新的內容並輸出),調用的時候可以有img、script、frame等等。詳細的其他使用方面請查看: http://www.npds.org/。
http://www.zeali.net/entry/129
http://www.rainway.org/2004/10/03/server-push/
http://tech.ccidnet.com/art/294/20030212/37827_1.html