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

PHP 長連接(Comet/Streaming)實作與 ob_flush/flush 避坑指南

     編輯:PHP 綜合知識

核心原理

PHP 預設輸出緩衝,瀏覽器需等腳本結束才收到內容。長連接需:

  1. set_time_limit(0) 移除執行時間限制。
  2. 迴圈中產生資料 → ob_flush() → flush() 強制推送至瀏覽器。
  3. sleep() 控制推送頻率。

基本範例:每 3 秒輸出一次時間

<?php
echo "每隔3秒輸出一次<br/>";
set_time_limit(0); // 關鍵:防止 30 秒超時

while (true) {
    echo date('H:i:s') . "<br/>";
    ob_flush(); // 刷新 PHP 內部緩衝
    flush();    // 刷新 Web Server 緩衝發送給瀏覽器
    sleep(3);
}

進階範例:固定 60 次輸出並保持 Keep-Alive

set_time_limit(0);
header('Connection: Keep-Alive');
header('Proxy-Connection: Keep-Alive');

for ($i = 0; $i < 60; $i++) {
    echo "text$i<br>";
    ob_flush();
    flush();
    sleep(1);
    clearstatcache(); // 清除檔案狀態緩存(可選)
}

⚠️ 兩大避坑須知

1. ob_flush() 必須在 flush() 之前

// ✅ 正確
ob_flush();
flush();

// ❌ 錯誤順序(Linux 下無輸出)
flush();
ob_flush();
Windows 上順序顛倒可能仍正常,但 Linux/Unix 環境下 必須先 ob_flush 再 flush。

2. 輸出內容需達到 output_buffering 門檻(預設 4096 bytes)

若內容過少,Web Server 會繼續緩衝不發送。解法:在迴圈前輸出足夠空白字元。

// 確保緩衝區滿 4096 bytes
echo str_repeat(' ', 4096);

for ($i = 10; $i > 0; $i--) {
    echo "$i<br/>";
    ob_flush();
    flush();
    sleep(1);
}
ob_end_flush(); // 結束輸出緩衝

常見問題排查

現象可能原因解決
瀏覽器一次性收到所有內容未呼叫 ob_flush/flush 或順序錯誤檢查順序、確保 output_buffering 門檻
連線中斷 (ERR_CONNECTION_RESET)腳本執行超時set_time_limit(0) 或 nginx proxy_read_timeout
記憶體耗盡無限迴圈未釋放資源加入迴圈上限、定期 gc_collect_cycles()

生產環境建議

  • Nginx + PHP-FPM 需關閉 fastcgi_buffering 或設定 proxy_buffering off。
  • Apache 需確保 mod_deflate 不攔截串流輸出。
  • 高併發場景建議改用 Swoole / Workerman 或 Server-Sent Events (SSE) / WebSocket,原生 PHP 長連接佔用一個 FPM worker,擴展性極差。

總結

掌握 set_time_limit(0)、ob_flush() → flush()、4096 bytes 門檻 三要素,即可在傳統 PHP-FPM 架構下實現簡易串流輸出。但務必評估併發壓力,必要時遷移至常駐記憶體框架。

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