這篇文章給大家分享了http 瀏覽器主動斷開連接與php主動斷開連接,有興趣的朋友可以看一看
摘要:事件起因是因為平時在開發中遇到的疑惑。一次是瀏覽器客戶端主動斷開了連線後,發現伺服器端的php腳本還在執行,以至於不知道怎麼讓腳本停下來。還有一次是有需求讓php腳本主動斷開連接,然後後續腳本繼續執行(一個耗時任務),所以有了這篇部落格。
在常用的LAMP組合下,我們認為,瀏覽器訪問一個php腳本,腳本開始執行,腳本輸出內容,並結束運行,apache回應http,瀏覽器收到http回應,顯示結果。
下來考慮下特殊的情況。
1、瀏覽器發送http請求,php執行了一個耗時任務(20s)(假設php的set_time_limit設定的是30s),在此期間瀏覽器無回應,使用者點擊瀏覽器X,瀏覽器主動斷開連接,php腳本是否仍繼續運作。
假設耗時任務是:計算fib(25),瀏覽器測試回應需要時間1.15s,每執行一次耗時任務,寫檔案Log寫一次,執行10次耗時任務,在執行第5次的時候,客戶端主動斷開連接,觀察情況。
程式碼如下:
<?phpfor ($i=0; $i < 10; $i++) { fib(25); setLog(date('H:i:s')); }function fib($n = 3){ if($n == 0){ return 1; } if($n == 1){ return 1; } return fib($n - 1) + fib($n -2); }function setLog( $massage, $path=''){ $log_path = empty($path)?'./log_'.date('Y-m-d').'.log':$path; $time = date('Y-m-d H:i:s'); $error_page = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; file_put_contents($log_path, "LOG TIME:".$time.PHP_EOL, FILE_APPEND); file_put_contents($log_path, "LOG URL:".$error_page.PHP_EOL, FILE_APPEND); if(is_array($massage)){ $massage = json_encode($massage); } file_put_contents($log_path, "LOG MESSAGE:".$massage.PHP_EOL.PHP_EOL, FILE_APPEND); }?>
瀏覽器在執行到5.44s的時候斷開了連線。
日誌顯示:腳本執行完了10次迴圈。
這與我們之前認為的不一樣;
2、優化一下,看到網上說,php判斷客戶端連接是否斷開,是在php往客戶端輸出內容的時候判斷的,那我們把測試程式碼修改一下:
<phpfor ($i=0; $i < 10; $i++) { fib(25); setLog(date('H:i:s')); echo "hello"; } //这里省略了fib和setLog函数 ?>
再次測試一下,發現和上一次的測試結果是一樣的。究其原因:php往客戶端輸出內容的時候,要有3個緩衝階段,分別是:
php buffer => web server buffer => browser buffer
只有當緩衝區滿了的時候才會輸出到客戶端,其實就是,後端每隔一段時間就會輸出內容到前端的原理。當然也是可以控制當緩衝區沒有滿的時候,也讓輸出到客戶端。
3、再修改測試程式碼,讓輸出客戶端的內容夠大:
<?php$re = "";for($i=0; $i < 10000; $i++){ $re .= "aa"; }for ($i=0; $i < 10; $i++) { fib(25); setLog(date('H:i:s')); echo $re; }//这里省略了fib和setLog函数?>
這次再測試,就會發現瀏覽器會隔一段時間就收到一些相應,而不是之前的demo,需要腳本完全執行完才輸出內容到客戶端。同時,這個時候關閉客戶端連接,伺服器端當再次向客戶端輸出內容的時候,就會檢查客戶端連接已經斷開了,這個時候腳本就會停止運行了。這是我們想要的測試結果。
4、再修改測試程式碼,這次不讓一次輸出一個很大的內容,而是有意操作緩衝區內容,讓雖然不夠從緩衝區輸出到客戶端的內容提前輸出到客戶端。
測試程式碼:
for ($i=0; $i < 10; $i++) { fib(25); setLog(date('H:i:s')); echo "hello " . date('H:i:s') . "<br>"; ob_flush(); flush(); } //这里省略了fib和setLog函数
小結:
#原則上用戶端主動斷開連接,php腳本即停止執行;
connection,当客户端收到响应头connection的值为close或者keep-alive,决定关闭当前tcp连接或者继续使用当前连接作下一次请求;
测试发现,当只指定conetent-length的时候也能达到php主动断开连接;
其实说是php主动断开连接,其实是php通知客户端主动断开的连接;
示例代码:
<?phpecho "hello world"; test();for ($i=0; $i < 10; $i++) { fib(25); setLog(date('H:i:s')); }function test(){ $size = ob_get_length(); header("content-length:" . $size); //header("connection:close"); ob_flush(); flush(); }//这里省略了fib和setLog函数?>
<完>
以上是http 瀏覽器主動斷開連接 與 php主動斷開連接的詳細內容。更多資訊請關注PHP中文網其他相關文章!