當前位置: 首頁> 最新文章列表> 使用socket_set_block 實現帶控制流的消息收發系統

使用socket_set_block 實現帶控制流的消息收發系統

gitbox 2025-05-29

1. 什麼是socket_set_blocking?

PHP 中的socket_set_blocking函數用來設置一個socket 資源的阻塞模式:

  • 阻塞模式(blocking):調用socket 相關函數時會等待操作完成,期間程序會停頓。

  • 非阻塞模式(non-blocking):調用socket 相關函數時立即返回,不會等待操作完成。

默認情況下,socket 是阻塞的。阻塞模式適合簡單同步場景,但對於高性能服務器,需要更細緻的控制流機制。

 bool socket_set_blocking ( resource $socket , bool $mode )
  • $socket :socket 資源。

  • $modetrue表示阻塞, false表示非阻塞。


2. 控制流的意義

控制流即對消息的發送與接收節奏進行管理,防止消息發送過快導致網絡擁堵、資源佔用過高或消息丟失。帶有控制流的設計可以實現:

  • 隊列消息緩衝,逐步發送。

  • 動態切換阻塞與非阻塞模式。

  • 超時處理和錯誤重試機制。


3. 設計思路

  • 服務器和客戶端均使用阻塞模式,保證發送和接收的穩定性。

  • 對消息發送進行隊列化,只有發送緩衝區有數據時才發送,防止阻塞等待。

  • 接收端設置合理的超時,避免長時間掛起。

  • 利用socket_select實現多路復用,監控讀寫事件,提升效率。


4. 示例代碼

下面是一個簡化的基於TCP 的PHP socket 服務端示例,演示瞭如何用socket_set_blocking控制阻塞模式,實現消息收發的流控:

 <?php
$host = "0.0.0.0";
$port = 12345;

// 創建socket
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($sock, $host, $port);
socket_listen($sock);

echo "Server started at $host:$port\n";

// 設置監聽socket為阻塞模式,接受連接時等待客戶端
socket_set_blocking($sock, true);

$clients = [];

while (true) {
    // 使用 socket_select 監聽活動連接
    $read = $clients;
    $read[] = $sock; // 加入監聽socket
    $write = [];
    $except = null;

    // 阻塞等待活動socket
    if (socket_select($read, $write, $except, 5) < 1) {
        continue; // 超時無活動
    }

    // 處理新連接
    if (in_array($sock, $read)) {
        $newClient = socket_accept($sock);
        if ($newClient !== false) {
            socket_set_blocking($newClient, true); // 設置客戶端socket為阻塞,保證消息完整
            $clients[] = $newClient;
            echo "New client connected\n";
        }
        unset($read[array_search($sock, $read)]);
    }

    // 處理已有客戶端消息
    foreach ($read as $client) {
        $data = socket_read($client, 2048, PHP_NORMAL_READ);
        if ($data === false || $data === '') {
            // 客戶端斷開連接
            echo "Client disconnected\n";
            socket_close($client);
            unset($clients[array_search($client, $clients)]);
            continue;
        }
        $data = trim($data);
        echo "Received: $data\n";

        // 簡單回顯,帶流控:發送前確保socket阻塞模式,防止寫入失敗
        socket_set_blocking($client, true);
        $sendResult = socket_write($client, "Echo: $data\n");
        if ($sendResult === false) {
            echo "Failed to send message to client\n";
        }
    }
}

5. 解析代碼的流控設計點

  • 阻塞模式的切換<br> 監聽socket 和客戶端socket 都設為阻塞,這樣在讀取和寫入數據時,可以保證數據的完整性,避免因非阻塞模式下的短讀短寫導致消息不完整

  • socket_select 監聽多路復用
    socket_select阻塞等待某個socket 可讀,提高CPU 利用率,避免死循環浪費資源。

  • 消息隊列控制(可擴展)
    示例中雖然直接讀寫,但可根據需求添加消息隊列,控制每次發送的消息大小和頻率,避免客戶端網絡擁塞。


6. 進一步優化建議

  • 使用非阻塞模式配合事件驅動庫(如libevent),提升高並發性能。

  • 引入消息序列號、確認機制,保障消息傳輸完整性。

  • 實現心跳包檢測連接狀態。

  • 使用socket_set_option優化TCP 參數,如設置TCP_NODELAY 以減少延遲。


7. 結語

通過合理運用PHP 的socket_set_blocking函數,結合socket_select事件監聽機制,能夠構建一個帶有控制流的高效消息收發系統。控制流不僅保證了消息傳輸的穩定性,還提升了系統的響應速度與資源利用率。希望本文示例和思路對你搭建自己的消息系統有所幫助。