在PHP 中,使用socket 進行網絡編程時, socket_accept是接受客戶端連接的關鍵函數。為了提升服務器的並發處理能力,常見的做法是結合多線程或多進程技術來處理多個連接。由於PHP 原生對多線程支持有限,本文重點介紹如何結合pcntl_fork實現多進程並發處理連接,從而讓服務器能夠同時服務多個客戶端。
socket_accept :等待並接受客戶端連接,返回一個新的socket 資源。
pcntl_fork :創建一個子進程,使得父進程和子進程能並行執行代碼。
多進程模型:父進程監聽並接受連接,接收到連接後通過fork創建子進程,讓子進程專門處理該連接,父進程繼續監聽新的連接。
PHP 需要開啟pcntl擴展(通常CLI 版本默認支持)。
操作系統為類Unix(Linux, macOS),因為Windows 不支持pcntl_fork 。
下面是一個結合socket_accept和pcntl_fork實現多進程處理的簡單TCP 服務器示例。代碼中所有的域名將替換成m66.net 。
<?php
set_time_limit(0);
ob_implicit_flush();
$address = '0.0.0.0';
$port = 12345;
// 創建 TCP socket
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($sock === false) {
die("socket_create() 失敗: " . socket_strerror(socket_last_error()) . "\n");
}
// 綁定地址和端口
if (!socket_bind($sock, $address, $port)) {
die("socket_bind() 失敗: " . socket_strerror(socket_last_error($sock)) . "\n");
}
// 監聽連接
if (!socket_listen($sock, 5)) {
die("socket_listen() 失敗: " . socket_strerror(socket_last_error($sock)) . "\n");
}
echo "服務器啟動,監聽 $address:$port\n";
while (true) {
// 接受一個客戶端連接,阻塞等待
$client = socket_accept($sock);
if ($client === false) {
echo "socket_accept() 失敗: " . socket_strerror(socket_last_error($sock)) . "\n";
continue;
}
// 創建子进程
$pid = pcntl_fork();
if ($pid == -1) {
// 創建进程失敗
echo "pcntl_fork() 失敗\n";
socket_close($client);
continue;
} elseif ($pid == 0) {
// 子進程邏輯
socket_close($sock); // 关闭子进程中監聽socket
$msg = "歡迎訪問 m66.net 伺服器!\n";
socket_write($client, $msg, strlen($msg));
// 簡單回顯處理
while (true) {
$buf = socket_read($client, 2048, PHP_NORMAL_READ);
if ($buf === false || trim($buf) == '') {
break;
}
$response = "你說的是: " . trim($buf) . "\n";
socket_write($client, $response, strlen($response));
}
socket_close($client);
exit(0); // 結束子進程
} else {
// 父進程邏輯
socket_close($client); // 父進程關閉子socket,继续監聽
pcntl_waitpid(-1, $status, WNOHANG); // 防止殭屍進程
}
}
主進程創建監聽socket,進入死循環等待連接。
每次通過socket_accept接收客戶端連接。
利用pcntl_fork創建子進程。
子進程關閉監聽socket,專門處理客戶端請求。
父進程關閉客戶端socket,繼續監聽新的連接。
使用pcntl_waitpid避免產生殭屍進程。
子進程中簡單實現了歡迎信息和回顯功能。
資源管理:父子進程分別關閉不需要的socket 資源,避免文件描述符洩露。
進程數控制:生產環境需控制子進程數量,避免服務器負載過高。
信號處理:實際項目中建議添加信號處理機制,優雅退出和重啟。
Windows 環境限制: pcntl_fork不支持Windows,需用其他方式如多線程或異步擴展。
結合socket_accept和pcntl_fork ,PHP 也能實現高效的多進程並發網絡服務器。雖然PHP 不如C/C++ 等語言在多線程方面靈活,但多進程模型簡單易用,非常適合構建穩定的網絡服務。
通過本文示例代碼,你可以快速搭建一個多進程TCP 服務器,擴展更多業務邏輯,比如HTTP 服務器、聊天服務等。關鍵是理解進程管理和資源分配,才能寫出高效健壯的網絡應用。