当前位置: 首页> 最新文章列表> 如何限制 socket_accept() 的最大连接数防止 DoS 攻击

如何限制 socket_accept() 的最大连接数防止 DoS 攻击

M66 2025-06-03

在使用 PHP 进行网络编程时,socket_accept() 是接受客户端连接的核心函数。面对 DoS(Denial of Service)攻击,攻击者通常会通过大量恶意连接请求,耗尽服务器资源,导致服务器无法正常响应合法用户请求。本文将讲解如何通过限制 socket_accept() 接受的最大连接数,有效防止服务器被恶意拖垮。

1. 理解 DoS 攻击与连接数限制

DoS 攻击中,攻击者制造大量连接请求占满服务器的并发连接数,导致服务器无法处理新的正常请求。限制最大连接数,确保服务器在资源许可范围内只处理一定数量的客户端连接,可以有效降低这种攻击带来的影响。

2. 使用 PHP socket_accept() 限制最大连接数的思路

  • 使用变量计数当前已建立的连接数。

  • 在接收到新的连接时,判断当前连接数是否超过限制。

  • 超过限制时拒绝连接(关闭新连接),不再调用 socket_accept() 处理。

  • 连接关闭时,及时减少连接计数。

3. 示例代码

下面的代码示范了如何在 PHP 中实现基于 socket_accept() 的最大连接数限制,假设最大连接数为 100:

<?php
set_time_limit(0);
error_reporting(E_ALL);

$address = '0.0.0.0';
$port = 12345;
$maxConnections = 100;
$currentConnections = 0;

// 创建 TCP Socket
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($sock, $address, $port) or die('绑定失败');
socket_listen($sock);

echo "服务器启动,监听 {$address}:{$port}\n";

$clients = [];

while (true) {
    // 判断是否超过最大连接数
    if ($currentConnections < $maxConnections) {
        // 非阻塞模式接受新连接
        socket_set_nonblock($sock);
        $client = @socket_accept($sock);

        if ($client !== false) {
            // 新连接成功,计数加一
            $currentConnections++;
            $clients[] = $client;

            // 设置客户端socket为非阻塞
            socket_set_nonblock($client);

            echo "新客户端连接,当前连接数: $currentConnections\n";
        }
    } else {
        // 超出最大连接数,拒绝新连接(可选等待短暂时间)
        usleep(100000); // 100ms
    }

    // 轮询处理已连接客户端的数据
    foreach ($clients as $key => $clientSocket) {
        $data = @socket_read($clientSocket, 2048, PHP_NORMAL_READ);

        if ($data === false) {
            // 连接断开,移除客户端
            socket_close($clientSocket);
            unset($clients[$key]);
            $currentConnections--;
            echo "客户端断开,当前连接数: $currentConnections\n";
            continue;
        } elseif ($data !== '') {
            $data = trim($data);
            if ($data === 'quit') {
                // 客户端主动断开连接
                socket_close($clientSocket);
                unset($clients[$key]);
                $currentConnections--;
                echo "客户端主动断开,当前连接数: $currentConnections\n";
                continue;
            }

            // 处理客户端发送的数据
            $response = "服务器收到: {$data}\n";
            socket_write($clientSocket, $response, strlen($response));
        }
    }

    usleep(50000); // 减少CPU占用
}
?>

4. 代码说明

  • 使用 $currentConnections 记录当前活跃连接数。

  • 只在未超出最大连接数时调用 socket_accept() 接收新连接。

  • 新连接创建后将客户端 socket 保存到 $clients 数组,并设置为非阻塞模式。

  • 通过轮询 $clients,读取客户端数据,响应后继续监听。

  • 如果客户端断开或者发送 quit 指令,关闭 socket 并减少连接计数。

  • 使用 usleep() 减少 CPU 过度占用。

5. 进一步防护建议

  • 设置超时:检测客户端连接空闲时间,超时自动断开。

  • 限制单IP连接数:防止单一IP制造大量连接。

  • 使用防火墙:在服务器层面限制异常连接。

  • 使用负载均衡:分散请求压力。

  • 监控日志:及时发现异常流量。

6. 结语

通过在 PHP 的 socket 服务器中限制最大连接数,可以有效抵御一定程度的 DoS 攻击,避免服务器资源被恶意耗尽。结合其他安全措施,能为服务器提供更坚实的防护,保障服务的稳定运行。