在 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 服务器、聊天服务等。关键是理解进程管理和资源分配,才能写出高效健壮的网络应用。