本文系統梳理 PHP 透過 fsockopen 實現非阻塞併發的演進路徑:同步阻塞 → stream_socket_client + stream_select(PHP 5+) → socket_* 擴充(PHP 4.1+) → 現代框架替代方案。
fsockopen (阻塞)
│
├─▶ stream_socket_client + STREAM_CLIENT_ASYNC_CONNECT + stream_select (PHP 5+, 推薦)
│
└─▶ socket_create + socket_set_nonblock + socket_connect + socket_select (PHP 4.1+, 相容舊版)
見 文章 42293 完整實作。核心優勢:
stream_select 管理。EINPROGRESS 錯誤碼。<?php
define('EINPROGRESS', 115); // Linux,其他平台請查 errno.h
function nb_connect(string $host, int $port, int $timeout, int &$errno, string &$errstr): ?resource {
$ip = gethostbyname($host);
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (!$sock) return null;
socket_set_nonblock($sock);
$connected = @socket_connect($sock, $ip, $port);
if ($connected || socket_last_error($sock) === EINPROGRESS) {
$errno = EINPROGRESS;
return $sock;
}
$errno = socket_last_error($sock);
$errstr = socket_strerror($errno);
socket_close($sock);
return null;
}
// 事件迴圈同 stream_select,改用 socket_read/write/close/select
?>
| 場景 | 推薦方案 |
|---|---|
| 傳統 PHP-FPM、不想引入框架 | Guzzle + curl_multi / stream_select 手寫 |
| 高併發、長連線、WebSocket | Swoole / OpenSwoole / RoadRunner |
| 微服務、非阻塞生態 | ReactPHP / Amp |
| 極簡環境、PHP 5.3+ | stream_socket_client + stream_select |