http 瀏覽器主動中斷連線 與 php主動中斷連線

來源:互聯網
上載者:User

本篇文章給大家分享了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指令碼即停止運行;

  • 但是前提是php知道用戶端中斷連線是怎麼知道的,只有當php輸出內容到用戶端(不是php緩衝區、不是web server緩衝區),php才知道用戶端串連中斷了,才會停止運行;

  • php輸出內容到用戶端,有兩種方式。一是填滿內容到緩衝區自動發送到用戶端;二是使用ob_flush,flush函數主動將緩衝區內容沖刷給用戶端;

  • php指令碼運行還受到內部的指令碼計時器限制,可以在php.ini或者宿主apache設定檔中配置,或者指令碼中通過set_time_limt函數設定;

  • 當用戶端主動中斷連線,而php指令碼沒有停止啟動並執行時候,還要受限制於指令碼計時器;

  • 當php指令碼設定ignore_user_abort(true); 則即使用戶端串連斷開,且php輸出內容到用戶端知道了用戶端串連斷開,也不會停止指令碼執行;

  • php內部,系統維護的串連狀態,可以通過函數connection_status的傳回值檢查,0 : normal; 1 : aborted(中斷連線); 2 : timeout; 改狀態的檢測也是需要php指令碼輸出內容到用戶端才會知道,否則一直都是0;

  • 另外還有一個函數也可以檢測用戶端串連是否斷開(connection_aborted),0正常,1斷開。

  • 有個奇怪的問題是,當用戶端串連已經斷開,php指令碼輸出兩次後,狀態位才變成1;

二、php伺服器端主動中斷連線

  要讓php主動中斷連線,要使用http回應標頭裡面的content-length和connection兩個欄位,意義分別為:

  • content-length,當用戶端收到的回應標頭content-length,則當相應體收到指定大小後,就會斷開與伺服器的串連;

  • 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函數?>



<完>

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.