首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 長連結實戰:set_time_limit(0) 配合 flush/ob_flush 實現即時資料推送

     編輯:PHP 綜合知識

核心概念:打破執行時間與輸出緩衝的雙重限制

PHP 預設腳本執行時間上限(通常 30 秒)與輸出緩衝機制,是實現長連結(Long-lived HTTP Connection)的兩大攔路虎。set_time_limit(0) 移除時間限制,flush() 與 ob_flush() 雙重清空緩衝區,才能讓瀏覽器即時接收資料流。

最小可行範例:每 5 秒推送一行文字

<?php
header("Content-Type: text/plain; charset=utf-8");
set_time_limit(0);               // 0 代表無限制
@ini_set('implicit_flush', 1);   // 建議開啟隱式刷新
@ini_set('zlib.output_compression', 0); // 關閉壓縮,避免干擾

$msg = "Hello World\n";
while (true) {                   // 無限迴圈模擬長連結
    echo $msg;
    ob_flush();                  // 刷新 PHP 輸出緩衝
    flush();                     // 刷新 Web Server 緩衝(Apache/Nginx)
    sleep(5);                    // 模擬業務間隔
}
?>

關鍵點深度解析

set_time_limit(0) 的作用域
僅影響當前腳本,若在 php.ini 設定 max_execution_time 為 0,則全域生效。注意:在安全模式或某些虛擬主機環境下可能被禁用。
為何需要 ob_flush() 再 flush()?
PHP 內部有輸出緩衝,Web Server(如 Apache mod_php、Nginx fastcgi)也有緩衡。ob_flush 先推送至 SAPI 層,flush 再推送至 TCP 連結。順序不可顛倒。
瀏覽器端行為
測試時請使用 curl -N 或瀏覽器直接訪問。Chrome 需收到約 256 bytes 以上才開始渲染,建議每次輸出補足長度或啟用 Content-Type: text/event-stream (SSE)。

實戰應用場景

  • 即時通訊/聊天室:Server-Sent Events (SSE) 簡易實現
  • 長時間任務進度回報:匯入導出、影片轉碼、爬蟲進度
  • 日誌尾端跟隨:tail -f 網頁版
  • IoT 設備狀態推送:避免輪詢開銷

進階優化與替代方案

方案優點缺點
PHP 原生長連結零依賴、部署簡單佔用 FPM 進程、難以水平擴展、易觸發 Proxy/負載均衡超時
Swoole / Workerman常駐記憶體、高併發、支援 WebSocket需獨立服務、學習曲線較陡
Node.js + Socket.io生態成熟、雙向通訊技術棧分裂、維護成本高
Managed 服務無運維、自動擴縮容成本較高、資料經第三方

常見坑位避雷

  1. Nginx proxy_buffering:預設開啟會緩衝後端輸出,需在 location 加 proxy_buffering off;
  2. Gzip 壓縮:zlib.output_compression 或 Nginx gzip 會導致內容一次性輸出,必須關閉。
  3. 防火牆/負載均衡閒置超時:通常 60~300 秒斷開長連結,需配置 heartbeat 或改用 WebSocket。
  4. 記憶體洩漏:長跑腳本務必定期 gc_collect_cycles(),避免循環引用堆積。

結語

set_time_limit(0) 配合雙重 flush 是 PHP 實現伺服器推送的經典技巧,適合中小型即時場景。若併發超過百級、需雙向通訊或長期維護,強烈建議遷移至 Swoole、Workerman 或引入專用訊息推送服務。選對工具,事半功倍。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved