本文目录导读:

- 使用
stream_socket_server()(基础方案) - 使用
pcntl多进程方案 - 使用 Swoole 扩展(推荐)
- 完整的客户端测试代码
- 使用 Workerman(另一个常见方案)
- 性能对比
- 安装建议
- 注意事项
我来详细介绍如何在PHP中创建TCP服务器,包含多种实现方案:
使用 stream_socket_server()(基础方案)
这是PHP内置的最简单方式:
<?php
// 创建TCP服务器
$server = stream_socket_server(
"tcp://0.0.0.0:8080",
$errno,
$errstr
);
if (!$server) {
die("无法创建服务器: $errstr ($errno)");
}
echo "TCP服务器已启动,监听 0.0.0.0:8080\n";
// 设置非阻塞模式
stream_set_blocking($server, false);
// 存储所有客户端连接
$clients = [$server];
while (true) {
$read = $clients;
$write = null;
$except = null;
// 使用select监听连接
if (stream_select($read, $write, $except, 0, 10000) > 0) {
// 新连接
if (in_array($server, $read)) {
$client = stream_socket_accept($server);
if ($client) {
stream_set_blocking($client, false);
$clients[] = $client;
echo "新客户端连接: " . stream_socket_get_name($client, true) . "\n";
}
// 移除服务器对象,避免重复处理
$key = array_search($server, $read);
unset($read[$key]);
}
// 处理客户端数据
foreach ($read as $client) {
$data = fread($client, 8192);
if ($data === false || $data === '') {
// 客户端断开
echo "客户端断开连接\n";
fclose($client);
$key = array_search($client, $clients);
unset($clients[$key]);
} else {
// 处理接收到的数据
echo "收到数据: " . trim($data) . "\n";
// 发送响应
fwrite($client, "服务器收到: " . $data);
// 如果收到exit命令,关闭连接
if (trim($data) === "exit") {
fclose($client);
$key = array_search($client, $clients);
unset($clients[$key]);
}
}
}
}
}
使用 pcntl 多进程方案
适合需要高并发的场景:
<?php
// 创建服务器
$server = stream_socket_server(
"tcp://0.0.0.0:8080",
$errno,
$errstr
);
if (!$server) {
die("无法创建服务器: $errstr ($errno)");
}
// fork 5个子进程
$workers = 5;
for ($i = 0; $i < $workers; $i++) {
$pid = pcntl_fork();
if ($pid == -1) {
die("无法创建子进程");
} elseif ($pid) {
// 父进程继续
continue;
} else {
// 子进程处理连接
while (true) {
$client = @stream_socket_accept($server);
if ($client) {
// 处理客户端请求
$pid = posix_getpid();
echo "进程 $pid 处理新连接\n";
// 读取数据
$request = fread($client, 8192);
echo "收到: " . $request . "\n";
// 发送响应
$response = "处理完成 (进程 $pid): " . $request;
fwrite($client, $response);
fclose($client);
}
usleep(100);
}
}
}
// 父进程等待子进程
while (true) {
$status = 0;
$pid = pcntl_wait($status);
echo "子进程 $pid 退出\n";
}
使用 Swoole 扩展(推荐)
Swoole是PHP最完善的TCP服务器解决方案:
<?php
// 创建Swoole TCP服务器
$server = new Swoole\Server('0.0.0.0', 8080);
// 设置运行参数
$server->set([
'worker_num' => 4, // worker进程数
'backlog' => 128, // 监听队列长度
'max_connection' => 10000, // 最大连接数
'daemonize' => false, // 是否守护进程化
]);
// 监听连接建立事件
$server->on('Connect', function ($server, $fd) {
echo "客户端连接: fd=$fd\n";
});
// 监听数据接收事件
$server->on('Receive', function ($server, $fd, $reactor_id, $data) {
echo "收到数据 fd=$fd: " . $data . "\n";
// 发送响应
$server->send($fd, "服务器收到: " . $data . "\n");
});
// 监听连接关闭事件
$server->on('Close', function ($server, $fd) {
echo "客户端断开: fd=$fd\n";
});
// 服务器启动
$server->start();
完整的客户端测试代码
<?php
// TCP客户端测试代码
$client = stream_socket_client(
"tcp://127.0.0.1:8080",
$errno,
$errstr,
30
);
if (!$client) {
echo "连接失败: $errstr ($errno)\n";
exit;
}
echo "连接成功,发送数据...\n";
// 发送数据
fwrite($client, "你好,服务器!");
// 读取响应
$response = fread($client, 8192);
echo "服务器响应: " . $response . "\n";
// 关闭连接
fclose($client);
使用 Workerman(另一个常见方案)
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
// 创建TCP服务
$tcp_worker = new Worker("tcp://0.0.0.0:8080");
// 设置进程数
$tcp_worker->count = 4;
// 当客户端连接时触发
$tcp_worker->onConnect = function($connection) {
echo "新连接\n";
};
// 当收到数据时触发
$tcp_worker->onMessage = function($connection, $data) {
$connection->send("收到: " . $data);
};
// 当连接关闭时触发
$tcp_worker->onClose = function($connection) {
echo "连接关闭\n";
};
// 启动服务
Worker::runAll();
性能对比
| 方案 | 并发能力 | 开发复杂度 | 扩展性 | 适用场景 |
|---|---|---|---|---|
| stream_socket | 低 | 简单 | 差 | 学习/小规模 |
| pcntl多进程 | 中 | 中等 | 一般 | 中等规模 |
| Swoole | 高 | 中等 | 好 | 生产环境 |
| Workerman | 高 | 简单 | 好 | 生产环境 |
安装建议
对于生产环境,推荐使用Swoole:
# 安装Swoole pecl install swoole # 或使用Docker docker run -p 8080:8080 -v $(pwd):/app php:8.2-cli \ sh -c "docker-php-ext-install swoole && php /app/server.php"
注意事项
- 超时处理:设置合理的超时时间
- 错误处理:完善异常和错误处理机制
- 资源管理:及时释放连接和资源
- 安全防护:防止恶意攻击和资源耗尽
- 日志记录:记录重要操作和错误信息
选择哪种方案取决于你的具体需求,生产环境推荐使用Swoole或Workerman。