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

PHP fsockopen() 實作 HTTP Client:GET/POST 請求、原始 Socket 通訊、超時控制與錯誤處理

     編輯:PHP 綜合知識

fsockopen() 是 PHP 底層**網路通訊基石**,可建立 TCP/UDP/Unix Socket 連線,**不依賴 cURL 擴充套件**,適合輕量環境、教學示範、特殊協定實作。本文詳細說明語法、HTTP/1.0 請求手工組裝、GET/POST 完整範例、非阻塞模式、SSL/TLS、超時控制與錯誤處理最佳實務。

一、語法與參數

fsockopen(
    string $hostname,
    int $port = -1,
    int &$errno = null,
    string &$errstr = null,
    float $timeout = ini_get('default_socket_timeout')
): resource|false
  • $hostname:支援 tcp://、udp://、ssl://、tls://、unix:// 封裝協定。
  • $port:目標埠號,-1 表示 Unix Socket。
  • $errno, $errstr:傳址回傳系統錯誤碼/訊息。
  • $timeout:連線階段超時 (秒),**不包含傳輸階段**;傳輸超時需 stream_set_timeout()。

二、HTTP/1.0 GET 請求最小範例

<?php
$host = 'www.example.com';
$port = 80;
$path = '/';
$fp = @fsockopen($host, $port, $errno, $errstr, 10);
if (!$fp) { die("連線失敗: $errstr ($errno)"); }

$out = "GET $path HTTP/1.0\r\n";
$out .= "Host: $host\r\n";
$out .= "Connection: close\r\n\r\n";

fwrite($fp, $out);
$response = '';
while (!feof($fp)) { $response .= fgets($fp, 4096); }
fclose($fp);

// 簡易分離 header/body
list($header, $body) = explode("\r\n\r\n", $response, 2);
echo $body;

三、HTTP/1.0 POST 請求完整範例 (含表單資料)

function httpPost(string $host, string $path, array $data, int $port = 80, float $timeout = 10): string {
    $body = http_build_query($data);
    $fp = @fsockopen($host, $port, $errno, $errstr, $timeout);
    if (!$fp) throw new Exception("Connect failed: $errstr ($errno)");

    $req  = "POST $path HTTP/1.0\r\n";
    $req .= "Host: $host\r\n";
    $req .= "Content-Type: application/x-www-form-urlencoded\r\n";
    $req .= "Content-Length: " . strlen($body) . "\r\n";
    $req .= "Connection: close\r\n\r\n";
    $req .= $body;

    fwrite($fp, $req);
    // 設定讀取超時 (傳輸階段)
    stream_set_timeout($fp, $timeout);

    $resp = '';
    $info = ['timed_out' => false];
    while (!feof($fp) && !$info['timed_out']) {
        $resp .= fgets($fp, 4096);
        $info = stream_get_meta_data($fp);
    }
    fclose($fp);

    // 簡易分離
    [$header, $body] = explode("\r\n\r\n", $resp, 2) + ['', ''];
    return $body;
}

// 使用
echo httpPost('httpbin.org', '/post', ['field1'=>'value1', 'field2'=>'value2']);

四、HTTPS (SSL/TLS) 連線

$fp = fsockopen('ssl://api.github.com', 443, $errno, $errstr, 10);
// 或
$fp = fsockopen('tls://api.github.com', 443, $errno, $errstr, 10);
// 其餘請求邏輯相同
// 注意:需驗證憑證時請改用 stream_context_create() 設定 verify_peer/cafile

五、非阻塞模式與多路複用

$fp = fsockopen('www.example.com', 80);
stream_set_blocking($fp, 0); // 非阻塞
// 使用 stream_select() 同時監聽多個 socket
$read = [$fp]; $write = []; $except = [];
if (stream_select($read, $write, $except, 5)) {
    // $fp 可讀/可寫
}

六、錯誤代碼速查 (常見 errno)

errno常數說明
111ECONNREFUSED連線被拒絕 (服務未啟動/防火牆)
110ETIMEDOUT連線逾時
113EHOSTUNREACH主機不可達
32EPIPE寫入斷管 (對端已關閉)
104ECONNRESET連線被重置

七、fsockopen vs cURL vs Guzzle 選用指南

場景推薦理由
生產環境 HTTP API 串接Guzzle / cURL完整重導向、Cookie、Keep-Alive、並發、中介軟體、測試雙工
無 cURL 擴充套件的受限環境fsockopen核心內建、零相依
自訂協定 (SMTP, POP3, WebSocket, DNS, 游戲協定)fsockopen / stream_socket_client完整控制幀格式、握手流程
教學/理解 HTTP 底層fsockopen手工組裝請求/回應,學習價值高
高併發非阻塞Swoole / OpenSwoole / ReactPHP事件驅動、協程、原生異步

八、最佳實務清單

  1. **永遠檢查回傳值**,用 @ 抑制警告並自行處理 $errno/$errstr。
  2. **設定兩層超時**:fsockopen(..., $connectTimeout) + stream_set_timeout($fp, $readTimeout)。
  3. **正確讀取回應**:使用 feof() 迴圈,避免 fread($fp, 8192) 卡住;大回應考慮 stream_get_contents()。
  4. **解析 HTTP 回應**:手工分離 header/body 易出錯,建議引入 http_parse_message() (pecl_http) 或自寫狀態機。
  5. **SSL 驗證**:生產環境 HTTPS **必須**啟用 verify_peer、cafile,否則遭中間人攻擊。
  6. **資源釋放**:所有路徑 (正常/異常/逾時) 皆呼叫 fclose($fp),建議用 try/finally。

fsockopen() 雖非現代 HTTP Client 首選,但作為**網路程式設計基石**、**無相依環境救生圈**、**自訂協定實作利器**,深入掌握其行為邊界對 PHP 開發者極具價值。

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