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

PHP Socket 函數完整參考手冊:從建立連線到資料收發

     編輯:PHP 相關知識

前言

PHP 的 socket_* 函數族是對 C 語言 Berkeley Socket API 的薄封裝,提供底層網路程式設計能力。本文整理常用函數分類說明,並附上實用範例:Echo Server (TCP)、UDP 遊戲伺服器查詢、客戶端連線。

核心函數分類速查表

1. 生命週期管理

函數說明
socket_create(domain, type, protocol)建立 Socket 資源。domain: AF_INET(IPv4)/AF_INET6/AF_UNIX;type: SOCK_STREAM(TCP)/SOCK_DGRAM(UDP);protocol: SOL_TCP/SOL_UDP/0。
socket_bind(socket, address, port)綁定 IP 與埠 (伺服端)。address 可為 IP 或 Unix socket 路徑。
socket_listen(socket, backlog)監聽連線,backlog 為等待隊列長度。
socket_accept(socket)阻塞接受新連線,返回新 Socket 資源 (用於該客戶端通訊)。
socket_connect(socket, address, port)客戶端主動連線至伺服器。
socket_close(socket)關閉 Socket 並釋放資源。

2. 資料收發

函數說明
socket_write(socket, buffer, length)發送資料。需指定長度,返回實際寫入位元組數。
socket_read(socket, length, type)讀取資料。type: PHP_BINARY_READ (二進制、含換行) / PHP_NORMAL_READ (讀到 \n/\r)。
socket_recv(socket, buf, len, flags)進階接收,flags 可用 MSG_PEEK (窺視不移除)、MSG_WAITALL (等滿 len)。
socket_send(socket, buf, len, flags)進階發送,flags 可用 MSG_DONTROUTE、MSG_OOB (帶外資料)。

3. 狀態與選項

函數說明
socket_get_option / socket_set_option獲取/設定 Socket 選項 (超時、緩衝區大小、非阻塞、KeepAlive 等)。
socket_set_nonblock(socket)設為非阻塞模式,配合 socket_select 實現多路復用。
socket_select(read, write, except, tv_sec, tv_usec)多路復用核心,監控多個 Socket 可讀/可寫/例外事件。
socket_last_error(socket)取得最後錯誤代碼。
socket_strerror(errno)將錯誤代碼轉為可讀字串。
socket_clear_error(socket)清除錯誤狀態。

實戰範例一:TCP Echo Server (CLI 守護進程)

<?php
set_time_limit(0);
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($socket, '0.0.0.0', 12345);
socket_listen($socket, 5);
echo "Echo Server started on port 12345\n";

while (true) {
    $client = socket_accept($socket);
    socket_write($client, "Connected. Type 'quit' to exit.\n");
    while (true) {
        $data = socket_read($client, 1024, PHP_NORMAL_READ);
        if ($data === false) break;
        $data = trim($data);
        if ($data === 'quit') break;
        socket_write($client, "ECHO: $data\n");
    }
    socket_close($client);
}
socket_close($socket);
?>

實戰範例二:UDP 遊戲伺服器查詢 (以 Return to Castle Wolfenstein 為例)

<?php
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ['sec'=>5, 'usec'=>0]); // 5 秒接收超時

$host = 'wolfmaster.idsoftware.com';
$port = 27950;
socket_connect($socket, $host, $port); // UDP "連線" 只是設定預設目標

// 發送查詢封包 (協議特定)
socket_write($socket, "\xFF\xFF\xFF\xFFgetservers\x00");

$servers = [];
while (($data = @socket_read($socket, 4096)) !== false) {
    // 解析回應封包 (略)
    // 每 7 位元組一筆: 4 bytes IP + 2 bytes port
    for ($i = 22; $i + 5 < strlen($data); $i += 7) {
        $ip = implode('.', array_map('ord', str_split(substr($data, $i+1, 4))));
        $port = (ord($data[$i+5]) << 8) + ord($data[$i+6]);
        $servers[] = compact('ip', 'port');
    }
}
socket_close($socket);
echo "

" . count($servers) . " Servers found

"; // 後續可對每台發送 getstatus 取得玩家、地圖資訊 ?>

實戰範例三:同步 HTTP 客戶端 (簡易版)

<?php
function http_get($url) {
    $parsed = parse_url($url);
    $host = $parsed['host'];
    $path = $parsed['path'] ?? '/';
    $port = $parsed['port'] ?? 80;

    $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    socket_connect($sock, $host, $port);
    $req = "GET $path HTTP/1.0\r\nHost: $host\r\nConnection: Close\r\n\r\n";
    socket_write($sock, $req);
    $resp = '';
    while ($buf = socket_read($sock, 4096)) $resp .= $buf;
    socket_close($sock);
    return $resp;
}
echo http_get('https://example.com/');
?>

進階主題:非阻塞多路復用 (Reactor 模式)

$sockets = [$listen_socket];
while (true) {
    $read = $sockets;
    $write = $except = null;
    if (socket_select($read, $write, $except, 1) > 0) {
        foreach ($read as $sock) {
            if ($sock === $listen_socket) {
                $client = socket_accept($sock);
                socket_set_nonblock($client);
                $sockets[] = $client;
            } else {
                $data = socket_read($sock, 4096);
                if ($data === '' || $data === false) {
                    socket_close($sock);
                    $sockets = array_diff($sockets, [$sock]);
                } else {
                    // 處理 $data,準備回應寫入 $write 陣列...
                }
            }
        }
    }
}

常見坑與最佳實踐

  • 阻塞預設:所有 socket_* 預設阻塞,長連線必須設超時 (SO_RCVTIMEO) 或改非阻塞。
  • 資料邊界:TCP 是流協議,socket_read 可能回傳不完整封包,應用層需自行定義協議 (長度前綴、分隔符)。
  • 錯誤處理:每次呼叫後檢查 socket_last_error(),區分 EAGAIN/EWOULDBLOCK (非阻塞無資料) 與真實錯誤。
  • 資源洩漏:異常分支務必 socket_close,長期運行程式建議定期 gc_collect_cycles()。
  • IPv6 相容:使用 AF_INET6 或 stream_socket_server 雙棧綁定。

結語

掌握 PHP Socket API 能讓你突破 HTTP 框架限制,開發即時通訊、遊戲伺服器、物聯網網關、自定義協議代理等系統級應用。建議對照 官方手冊 深入研讀各函數參數細節。

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