當前位置: 首頁> 最新文章列表> [如何通過socket_export_stream 實現客戶端與服務器的雙向通信機制?

[如何通過socket_export_stream 實現客戶端與服務器的雙向通信機制?

M66 2025-06-22

在PHP 的網絡編程中, socket_*系列函數為開發者提供了底層的網絡通信能力。雖然stream_socket_*系列函數更為高級且易用,但在某些對底層控制要求更高的場景中, socket_*仍然具有不可替代的優勢。本文將介紹如何通過socket_export_stream將底層socket 轉換為stream,從而實現客戶端與服務器之間的雙向通信機制。

什麼是socket_export_stream?

socket_export_stream是PHP 提供的一個函數,用於將底層socket 資源導出為stream(流)資源,使得可以使用如fread()fwrite()這樣熟悉的文件流函數來操作socket 數據。這種方式結合了底層socket 的靈活性與stream API 的易用性。

 stream socket_export_stream(Socket $socket): resource|false

返回的是一個stream類型的資源,可用於與fopenstream_selectfgets等函數協同工作。


1. 創建服務端Socket

服務端通過socket_create()創建一個TCP 套接字,並綁定到一個本地地址與端口。

 $serverSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($serverSocket, '0.0.0.0', 9501);
socket_listen($serverSocket);
echo "服務器已啟動,監聽端口 9501...\n";

2. 接受連接並導出為Stream

服務端阻塞等待客戶端連接請求,並將連接資源導出為可讀寫的流。

 while (true) {
    $clientSocket = socket_accept($serverSocket);
    if ($clientSocket === false) {
        echo "接受連接失敗\n";
        continue;
    }

    $clientStream = socket_export_stream($clientSocket);
    if ($clientStream === false) {
        echo "導出 stream 失敗\n";
        socket_close($clientSocket);
        continue;
    }

    fwrite($clientStream, "歡迎連接到 m66.net 的服務器\n");
    
    while (!feof($clientStream)) {
        $data = fgets($clientStream);
        if ($data === false) break;
        echo "客戶端說: $data";
        fwrite($clientStream, "你說的是:$data");
    }

    fclose($clientStream);
    socket_close($clientSocket);
}

3. 客戶端連接服務器

客戶端同樣使用socket_create連接到服務端,然後使用socket_export_stream進行數據讀寫。

 $client = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($client, 'm66.net', 9501);

$stream = socket_export_stream($client);
if ($stream === false) {
    echo "導出 stream 失敗\n";
    exit(1);
}

echo fgets($stream); // 接收歡迎消息

fwrite($stream, "你好,伺服器!\n");
echo fgets($stream); // 讀取回顯

fclose($stream);
socket_close($client);

優勢與註意事項

優勢

  • 代碼簡潔:stream 接口簡化了socket 數據讀寫流程;

  • 兼容性高:可以與stream_selectstream_set_blocking等函數配合使用;

  • 雙向通信自然流暢:通過循環讀寫即可實現實時響應。

注意事項

  • socket_export_stream只能用於已連接的socket;

  • 使用完畢後需關閉stream 與socket,防止資源洩露;

  • 網絡通信應考慮異常處理與超時控制,避免阻塞或崩潰。