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

PHP Socket 通信完整指南:從 TCP/UDP 原理到生產級封裝類實戰

     編輯:PHP 相關知識

深入掌握 PHP Socket 開發:原理、流程、函數表、客戶端/服務端實現與類封裝

Socket 是應用層與 TCP/IP 協議棧交互的門面模式封裝。本文系統梳理 Socket 核心概念、通信流程、PHP 內建函數速查,並提供可直接用於生產的 ServerSocket / ClientSocket 封裝類。

核心概念速覽

協議全稱特點
TCPTransmission Control Protocol面向連接、可靠、有序、流式、開銷大
UDPUser Datagram Protocol無連接、不可靠、無序、數據報、開銷小、適合廣播/視頻

Socket 位於應用層與傳輸層之間,屏蔽了協議細節,提供統一介面:create → bind → listen → accept → read/write → close。

PHP Socket 核心函數速查表

// 生命週期
socket_create()      // 建立 socket 資源
socket_bind()        // 綁定 IP:PORT
socket_listen()      // 監聽連接隊列
socket_accept()      // 接受連接,返回新 socket
socket_connect()     // 客戶端發起連接

// 數據收發
socket_read()        // 讀取指定長度
socket_write()       // 寫入緩衝區
socket_recv()        // 從已連接 socket 讀取
socket_send()        // 發送到已連接 socket

// 工具
socket_close()       // 關閉資源
socket_last_error()  // 獲取錯誤碼
socket_strerror()    // 錯誤碼轉文本
socket_set_nonblock() // 非阻塞模式
socket_select()      // I/O 多路複用(關鍵!)
...

最小化服務端示例 (CLI 運行)

<?php
set_time_limit(0);
$host = '127.0.0.1'; $port = 1935;

$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($sock, $host, $port);
socket_listen($sock, 5);

echo "Server started on $host:$port\n";

while (true) {
    $client = socket_accept($sock);
    $input = socket_read($client, 8192);
    echo "Received: $input\n";
    $reply = "Server echo: $input";
    socket_write($client, $reply);
    socket_close($client);
}
socket_close($sock);

最小化客戶端示例

<?php
$host = '127.0.0.1'; $port = 1935;
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($sock, $host, $port);

$msg = "Hello from Client\n";
socket_write($sock, $msg);
$resp = socket_read($sock, 8192);
echo "Server reply: $resp\n";
socket_close($sock);

關鍵運行提示

  • 服務端必須在 CLI 模式運行(php server.php),不可用 CGI/瀏覽器訪問。
  • 驗證端口佔用:netstat -ano | findstr 1935 (Win) / ss -ltnp | grep 1935 (Linux)。
  • 生產環境需處理:非阻塞 + socket_select 多路複用、心跳檢測、協議封裝(長度前綴/分隔符)、異常重連、SSL/TLS 加密。

生產級封裝類:ServerSocket

<?php
class ServerSocket {
    private $host, $port, $master, $clients = [];

    public function __construct(string $host, int $port) {
        if (!extension_loaded('sockets')) die("請啟用 sockets 擴展");
        $this->host = $host; $this->port = $port;
        $this->initMaster();
    }

    private function initMaster() {
        $this->master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1);
        socket_bind($this->master, $this->host, $this->port);
        socket_listen($this->master, SOMAXCONN);
        $this->clients[] = $this->master;
    }

    public function run() {
        while (true) {
            $read = $this->clients;
            $write = $except = null;
            if (socket_select($read, $write, $except, null) < 1) continue;

            foreach ($read as $sock) {
                if ($sock === $this->master) {
                    // 新連接
                    $client = socket_accept($this->master);
                    $this->clients[] = $client;
                    echo "New client connected\n";
                } else {
                    // 數據到達
                    $data = @socket_read($sock, 8192, PHP_BINARY_READ);
                    if ($data === false || $data === '') {
                        // 斷開
                        $idx = array_search($sock, $this->clients, true);
                        if ($idx !== false) unset($this->clients[$idx]);
                        socket_close($sock);
                        continue;
                    }
                    // 業務處理(示例:回射)
                    $reply = $this->handle($data);
                    socket_write($sock, $reply);
                }
            }
        }
    }

    protected function handle(string $data): string {
        return "Echo: $data";
    }

    public function __destruct() {
        foreach ($this->clients as $sock) @socket_close($sock);
    }
}

// 使用
$server = new ServerSocket('0.0.0.0', 9501);
$server->run();

生產級封裝類:ClientSocket

<?php
class ClientSocket {
    private $host, $port, $sock, $timeout = 5.0;

    public function __construct(string $host, int $port, float $timeout = 5.0) {
        $this->host = $host; $this->port = $port; $this->timeout = $timeout;
        $this->connect();
    }

    private function connect() {
        $this->sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        socket_set_option($this->sock, SOL_SOCKET, SO_RCVTIMEO, ['sec' => (int)$this->timeout, 'usec' => 0]);
        socket_set_option($this->sock, SOL_SOCKET, SO_SNDTIMEO, ['sec' => (int)$this->timeout, 'usec' => 0]);
        if (!@socket_connect($this->sock, $this->host, $this->port)) {
            throw new RuntimeException("Connect failed: " . socket_strerror(socket_last_error()));
        }
    }

    public function send(string $data): string {
        socket_write($this->sock, $data);
        $buffer = '';
        while ($chunk = @socket_read($this->sock, 4096)) {
            $buffer .= $chunk;
            if (strlen($chunk) < 4096) break; // 簡易判斷結束
        }
        return $buffer;
    }

    public function close() {
        if ($this->sock) { socket_close($this->sock); $this->sock = null; }
    }

    public function __destruct() { $this->close(); }
}

// 使用
$client = new ClientSocket('127.0.0.1', 9501);
echo $client->send("Hello\n");
$client->close();

架構演進建議

  • 高併發長連接:遷移至 Swoole / OpenSwoole / RoadRunner,原生 PHP 處理數萬連接極其吃力。
  • WebSocket:引入 textalk/websocket 或 Swoole 內建 WebSocket 伺服器。
  • 協議設計:採用 長度前綴 + JSON/Protobuf 避免粘包/拆包。
  • 監控:集成 Prometheus 指標(連接數、QPS、延遲、錯誤率)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved