http 瀏覽器主動斷開連接 與 php主動斷開連接

不言
發布: 2023-03-22 22:36:02
原創
5015 人瀏覽過

這篇文章給大家分享了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(&#39;H:i:s&#39;));
}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=&#39;&#39;){
    $log_path = empty($path)?&#39;./log_&#39;.date(&#39;Y-m-d&#39;).&#39;.log&#39;:$path;    $time = date(&#39;Y-m-d H:i:s&#39;);    $error_page = &#39;http://&#39; . $_SERVER[&#39;HTTP_HOST&#39;] . $_SERVER[&#39;REQUEST_URI&#39;];
    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(&#39;H:i:s&#39;));    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(&#39;H:i:s&#39;));    echo $re;
}//这里省略了fib和setLog函数?>
登入後複製

  這次再測試,就會發現瀏覽器會隔一段時間就收到一些相應,而不是之前的demo,需要腳本完全執行完才輸出內容到客戶端。同時,這個時候關閉客戶端連接,伺服器端當再次向客戶端輸出內容的時候,就會檢查客戶端連接已經斷開了,這個時候腳本就會停止運行了。這是我們想要的測試結果。

  4、再修改測試程式碼,這次不讓一次輸出一個很大的內容,而是有意操作緩衝區內容,讓雖然不夠從緩衝區輸出到客戶端的內容提前輸出到客戶端。
測試程式碼:

for ($i=0; $i < 10; $i++) { 
    fib(25);    setLog(date(&#39;H:i:s&#39;));    echo "hello " . date(&#39;H:i:s&#39;) . "<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(&#39;H:i:s&#39;));
}function test(){
    $size = ob_get_length();
    header("content-length:" . $size);    //header("connection:close");
    ob_flush();
    flush();
}//这里省略了fib和setLog函数?>
登入後複製



<完>



以上是http 瀏覽器主動斷開連接 與 php主動斷開連接的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!