當前位置: 首頁> 最新文章列表> socket_set_option 和socket_select 結合使用實現多路復用

socket_set_option 和socket_select 結合使用實現多路復用

gitbox 2025-05-26

在PHP 網絡編程中,處理多路復用(Multiplexing)是實現高效網絡服務的關鍵技術。 socket_set_optionsocket_select作為PHP socket 編程中的兩個重要函數,很多開發者會疑惑它們是否可以一起使用,尤其是在實現多路復用時該如何正確搭配。

本文將詳細講解socket_set_optionsocket_select的作用,探討它們能否一起用,並介紹如何用它們實現多路復用。


1. socket_set_option 和socket_select 的基本作用

socket_set_option

socket_set_option用於給套接字設置選項,比如超時時間、是否重用地址、發送/接收緩衝區大小等。它的作用是調整socket 的行為特性。

 socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);

上面代碼為socket 設置了地址重用選項,常用於服務器重啟時快速綁定端口。

socket_select

socket_select是實現多路復用的關鍵函數。它用於監聽多個socket,當其中一個或多個socket 準備好讀寫時,函數返回。這樣可以讓單線程程序同時處理多個連接。

 $read = [$socket1, $socket2];
$write = null;
$except = null;
$timeout = 5;

$num_changed = socket_select($read, $write, $except, $timeout);

socket_select通過修改$read$write$except數組來返回那些準備好的socket。


2. socket_set_option 和socket_select 能一起用嗎?

答案是可以,但兩者功能不同,配合使用時應清晰區分用途:

  • socket_set_option用於配置socket 的行為(比如超時、緩衝區等)。

  • socket_select用於監聽多個socket 是否可讀、可寫或有異常。

多路復用主要依賴socket_select ,而socket_set_option只是調整socket 的屬性,通常是在socket 創建後、 socket_select使用前設置。


3. 使用socket_set_option 配合socket_select 實現多路復用示例

以下是一個簡單的服務器示例,展示如何用socket_set_option設置socket 選項,同時使用socket_select實現多路復用監聽多個客戶端連接。

 <?php
// 創建 TCP socket
$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1);

// 綁定端口
socket_bind($server, '0.0.0.0', 8080);
socket_listen($server);

$clients = [];
$read = [$server];

while (true) {
    $readSockets = $read;
    $write = null;
    $except = null;

    // 監聽多個 socket 的變化
    $numChanged = socket_select($readSockets, $write, $except, 5);

    if ($numChanged === false) {
        echo "socket_select 出錯\n";
        break;
    } elseif ($numChanged > 0) {
        // 監聽到新的客戶端連接
        if (in_array($server, $readSockets)) {
            $newClient = socket_accept($server);
            if ($newClient !== false) {
                socket_set_option($newClient, SOL_SOCKET, SO_RCVTIMEO, ["sec"=>5, "usec"=>0]);
                $clients[] = $newClient;
                $read[] = $newClient;
                echo "新客戶端連接\n";
            }
            unset($readSockets[array_search($server, $readSockets)]);
        }

        // 處理已有客戶端發送的數據
        foreach ($readSockets as $socket) {
            $data = socket_read($socket, 1024, PHP_NORMAL_READ);
            if ($data === false || $data === '') {
                // 連接關閉
                socket_close($socket);
                unset($clients[array_search($socket, $clients)]);
                unset($read[array_search($socket, $read)]);
                echo "客戶端斷開\n";
            } else {
                $data = trim($data);
                echo "收到客戶端數據: $data\n";
                // 發送響應
                socket_write($socket, "服務器已收到: $data\n");
            }
        }
    }
}
socket_close($server);

關鍵點說明:

  • 服務器套接字$serversocket_set_option設置了SO_REUSEADDR ,保證端口快速重用。

  • 新客戶端連接建立後,也用socket_set_option設置了接收超時選項。

  • socket_select監聽所有活躍的客戶端socket 和服務器socket,確保多路復用機制正常工作。


4. 結論

  • socket_set_optionsocket_select功能不同,但可以且應該結合使用。

  • socket_set_option負責配置socket 參數,優化網絡性能和行為。

  • socket_select負責多路復用,監聽多個socket 事件。

  • 合理使用這兩個函數,能夠寫出高效、穩定的網絡服務器程序。


如果想深入學習PHP socket 多路復用,也可以參考官方文檔及相關網絡編程書籍,掌握更多細節和高級技巧。


文章中示例的URL 域名如下:

 $url = "https://gitbox.net/api/socket_demo";