程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> PHP 在 Nginx 下主動斷開連接 Connection Close 與 ignore_user_abort 後台運行

PHP 在 Nginx 下主動斷開連接 Connection Close 與 ignore_user_abort 後台運行

編輯:關於PHP編程

PHP 在 Nginx 下主動斷開連接 Connection Close 與 ignore_user_abort 後台運行


這兩天弄個PHP調用 SVN 同步 update 多台服務器更新的程序,為了避免 commit 的時候不會被阻塞卡半天得想個辦法只請求觸發,而不需要等待程序 update 完成返回結果這樣耗時太長,所以研究過了下如何讓PHP主動斷開連接的方法。搞了一下午,發現很多問題,還好最終還是弄出來了,主要是 Nginx 太坑。。


廢話不多說,下面上代碼:


PHP


/**
 * 主動斷開與客戶端浏覽器的連接
 * 如果是 Nginx 服務器需要輸出大於等於 fastcgi_buffer_size 緩存的數據才能即時輸出 header 斷開連接, 若還是不行可嘗試關閉 gzip
 * 如: fastcgi_buffer_size 64k; 即: 需要 64*1024 字符(可多不可少),
 * 可使用 str_repeat(' ', 65536); 另外 str_repeat('          ', 6554); 這種方式其實生成速度更慢
 * @param null|string $str 當前輸出的內容, 若無需輸出則設置為空
 */
public function connectionClose($str = null) {
    $str = ob_get_contents() . $str;
    // 若實際輸出內容長度小於該值將可能導致主動斷開失敗
    header('Content-Length: '. strlen($str));
    Header::connectionClose();
    ob_start();
    echo $str;
    ob_flush();
    flush();
}

補充說明下:

對於 apache 一般沒什問題,我一開始在 windows 上用的 xampp 調試的 沒發現什麼問題,結果到服務器上是 Nginx ,死活不行,崩潰了一下午,後來才反映過來是 Nginx 的 fastcgi_buffer 的問題。

各種情況測試了N多次,應該沒什麼 BUG 了。。。


另外再說說 ignore_user_abort() 函數的問題

當浏覽器關閉後,決定程序是否還會在後台繼續執行,(下圖的例子中,你在測試時不一定非要設置為永不超時 limit 0 ,設置一兩分鐘就行了,否則可能重啟 HTTP 服務需要很長時間)


PHP


簡單來說,如果你要用戶浏覽器關閉後還需要程序繼續執行,那麼你必須加上下面這句代碼:

ignore_user_abort(true);

但根據你後面程序(主要是 while 死循環)的情況不同而有些許不同:

一般在程序中你可以監控連接狀態進行控制:

$isAborted = connection_aborted();
$status = connection_status();
if (0 !== $status || $isAborted) {
    break;
}

但這兩個函數要想正常工作得有個前提,就是你的程序必須要有輸出內容,且大於當前WebServer 的輸出緩存,這樣才會起作用。

如果你只是簡單的輸出一個空格 echo ’ ‘; 可能得循環幾千次才會判斷到,所以為了更即時的檢測到狀態你必須每次循環時輸出足夠多的內容才會觸發狀態檢測。

所以這裡也經常會遇到一個問題:當浏覽器斷開後,即使沒有使用 ignore_user_abort(true); 但因為沒有任何輸出,導致程序仍然會繼續執行,死循環會一直跑,如果設置了超時那還好,否則就真死掉了。


下面貼上測試代碼(貼個圖主要是為了防盜 嘿嘿~)


set_time_limit(0);

ignore_user_abort(true);

while (1) {
    echo str_repeat(' ', 65536);
    $isAborted = connection_aborted();
    $status = connection_status();
    file_put_contents('test.txt', 'time: '. time() .'; abroted:'. $isAborted .'; status: '. $status);
    if (0 !== $status || $isAborted) {
        break;
    }
    sleep(2);
}

你可以試試注釋掉這句
// echo str_repeat(’ ‘, 65536);
另外
set_time_limit(0); 最好也別用 0

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved