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

PHP Socket 連線與讀寫超時完整解決方案:stream 函式實戰應用

     編輯:PHP 綜合知識

PHP 的 fsockopen() 雖支援連線超時參數,但缺乏連線建立後的資料讀寫超時控制。透過 Stream 相關函式(stream_set_blocking、stream_set_timeout、stream_get_meta_data),可完整實作連線、寫入、讀取各階段的超時偵測與處理。

核心 Stream 函式說明

函式用途關鍵參數
stream_set_blocking($fp, false) 設定非阻塞模式,避免 fgets()/fread() 因無資料而無限等待 false = 非阻塞;true = 阻塞(預設)
stream_set_timeout($fp, 10) 設定資料流操作超時秒數,需在連線成功後立即呼叫 秒數(整數),也可用陣列指定秒與微秒
stream_get_meta_data($fp) 取得資料流中繼資料,包含 timed_out 布林值判斷是否超時 回傳陣列:['timed_out' => true/false, 'blocked' => 1, 'eof' => ...]

完整實作程式碼

<?php
$ip = '127.0.0.1';
$port = 80;
$packet = "GET / HTTP/1.1\r\nHost: $ip\r\nConnection: Close\r\n\r\n";

$fp = @fsockopen($ip, $port, $errNo, $errstr, 30); // 連線超時 30 秒
if (!$fp) {
    die("Connection failed: $errstr ($errNo)");
}

// 關鍵:連線成功後立即設定讀寫超時
stream_set_timeout($fp, 3); // 3 秒讀寫超時
// stream_set_blocking($fp, false); // 視需求啟用非阻塞

// 發送資料
fwrite($fp, $packet);
$status = stream_get_meta_data($fp);
if ($status['timed_out']) {
    echo "Write timed out";
    fclose($fp);
    exit;
}

// 讀取回應
$buf = fread($fp, 4096);
$status = stream_get_meta_data($fp);
if ($status['timed_out']) {
    echo "Read timed out";
    fclose($fp);
    exit;
}

echo "Response received: " . strlen($buf) . " bytes";
fclose($fp);
?>

關鍵實作細節

  1. 超時設定時機:stream_set_timeout() 必須在 fsockopen() 成功後、任何讀寫操作前呼叫。
  2. 每次讀寫後檢查:每次 fwrite()、fread() 後需立即呼叫 stream_get_meta_data() 檢查 timed_out,因超時狀態不會自動重置。
  3. 非阻塞模式選用:若需同時處理多連線或輪詢,設定 stream_set_blocking($fp, false),搭配 stream_select() 使用。
  4. 錯誤處理:超時時應關閉連線並記錄日誌,避免資源洩漏。

常見誤區提醒

  • ❌ 以為 fsockopen 的第 5 參數能控制讀寫超時(實為連線超時)。
  • ❌ 僅在開頭設定一次超時,卻在長時間傳輸中未重新檢查。
  • ❌ 忽略 stream_get_meta_data 回傳的 blocked、eof 等狀態資訊。

延伸應用建議

實際專案建議封裝為可重用的 SocketClient 類別,整合重試機制、SSL/TLS 支援(stream_socket_client 搭配 ssl://)、協定解析(HTTP、自訂協定)等。更多 Socket 進階技巧請參考專題:《PHP Socket 用法總結》。

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