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

PHP Socket 長連線實作:單次連線多次發送 HTTP 請求

     編輯:PHP 綜合知識

核心概念

HTTP/1.1 預設支援 Connection: Keep-Alive,允許單一 TCP 連線發送多個請求,減少三次握手開銷。PHP 透過 fsockopen() 可手動控制 Socket 連線。

Client 端實作

<?php
/**
 * 發送多次 HTTP 請求於單一 Socket 連線
 */
function sendMultipleRequests(string $host, int $port, int $count = 5): void
{
    // 建立連線
    $conn = @fsockopen($host, $port, $errno, $errstr, 5);
    if (!$conn) {
        throw new RuntimeException("連線失敗 [$errno]: $errstr");
    }

    // 設定逾時
    stream_set_timeout($conn, 5);

    for ($i = 0; $i < $count; $i++) {
        $postData = "user_name=admin{$i}";
        $response = sendHttpRequest($conn, $host, $postData);
        
        echo "請求 #{$i}: " . strlen($response) . " bytes 回應\n";
        
        // 避免發送過快
        usleep(100000); // 100ms
    }

    fclose($conn);
}

/**
 * 發送單一 HTTP/1.1 請求並讀取完整回應
 */
function sendHttpRequest($conn, string $host, string $body): string
{
    $headers = [
        "POST /test.php HTTP/1.1",
        "Host: {$host}",
        "Content-Type: application/x-www-form-urlencoded",
        "Content-Length: " . strlen($body),
        "Connection: Keep-Alive",
        "",  // 空行分隔 header 與 body
        $body,
        ""
    ];

    $request = implode("\r\n", $headers);
    fwrite($conn, $request);

    // 讀取回應
    $response = '';
    while (!feof($conn)) {
        $chunk = fread($conn, 8192);
        if ($chunk === '') break;
        $response .= $chunk;
        
        // 簡易判斷回應結束(實際應解析 Content-Length 或 Transfer-Encoding)
        if (strpos($response, "\r\n\r\n") !== false && 
            preg_match('/\r\n\r\n(.*)$/s', $response, $m)) {
            // 這裡簡化處理,實際需完整解析 HTTP 回應
        }
    }
    return $response;
}

// 執行
sendMultipleRequests('127.0.0.1', 80, 5);

Server 端測試腳本 (test.php)

<?php
// 記錄接收到的資料
$logFile = __DIR__ . '/received.log';
$data = $_POST['user_name'] ?? 'no-data';
$timestamp = date('Y-m-d H:i:s');
file_put_contents($logFile, "{$timestamp} - {$data}\n", FILE_APPEND);

// 簡單回應
echo "OK: {$data}";

關鍵技術細節

關鍵點說明
Connection: Keep-Alive告知伺服器保持連線,不關閉 TCP
Content-Length必須精確,伺服器才知道何時結束讀取 body
\r\n\r\n 分隔Header 與 Body 必須以雙 CRLF 分隔
回應讀取需解析 Content-Length 或 Chunked 編碼判斷結束
錯誤處理網路中斷、逾時、伺服器主動關閉需妥善處理

進階改進方向

  • 完整 HTTP 回應解析器(支援 Chunked、Gzip)
  • 連線池管理(複用多個 Keep-Alive 連線)
  • 非同步 I/O(stream_select / Swoole / Amp)
  • HTTPS 支援(stream_socket_client + SSL context)
  • 自動重連與熔斷機制

生產環境建議

💡 實務上建議:
除非有特殊需求(如高頻即時推送、舊系統整合),否則優先使用成熟的 HTTP Client 庫:
  • Guzzle - 功能完整、支援異步、中介軟體
  • Symfony HttpClient - 現代化、PSR-18 相容
  • Swoole Coroutine Http\Client - 協程非阻塞、極高效能
自行實作 Socket 易踩坑(編碼、逾時、連線狀態管理),維護成本高。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved