当前位置: 首页> 最新文章列表> [如何通过 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,防止资源泄露;

  • 网络通信应考虑异常处理与超时控制,避免阻塞或崩溃。