當前位置: 首頁> 最新文章列表> 如何用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 攻擊,避免服務器資源被惡意耗盡。結合其他安全措施,能為服務器提供更堅實的防護,保障服務的穩定運行。