ZetCode

PHP socket_set_blocking 函数

最后修改于 2025 年 4 月 4 日

PHP 的 socket_set_blocking 函数用于控制套接字的阻塞模式。它决定了套接字操作是否会等待完成。

基本定义

socket_set_blocking 将套接字设置为阻塞或非阻塞模式。在阻塞模式下,操作会一直等待直到可以完成。

语法:socket_set_blocking(Socket $socket, bool $enable): bool。成功时返回 true,失败时返回 false。会影响所有后续操作。

基本阻塞套接字示例

本示例演示了为简单的 TCP 客户端创建一个阻塞套接字。

blocking_socket.php
<?php

declare(strict_types=1);

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
    die("Socket creation failed");
}

// Set socket to blocking mode
socket_set_blocking($socket, true);

$connected = socket_connect($socket, 'example.com', 80);
if ($connected === false) {
    die("Connection failed");
}

echo "Connected in blocking mode\n";
socket_close($socket);

这会创建一个阻塞模式的 TCP 套接字。connect 操作将一直等待直到成功或失败。对于基本操作,阻塞模式更简单。

非阻塞套接字示例

这展示了如何为异步操作创建非阻塞套接字。

non_blocking_socket.php
<?php

declare(strict_types=1);

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
    die("Socket creation failed");
}

// Set socket to non-blocking mode
socket_set_blocking($socket, false);

$connected = socket_connect($socket, 'example.com', 80);
if ($connected === false) {
    $error = socket_last_error($socket);
    if ($error !== SOCKET_EINPROGRESS) {
        die("Connection failed");
    }
    echo "Connection in progress\n";
}

socket_close($socket);

非阻塞模式会立即返回。代码必须处理 EINPROGRESS 错误。这允许进行异步网络编程。

模式切换

本示例演示了在阻塞模式之间动态切换。

mode_switching.php
<?php

declare(strict_types=1);

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, 'example.com', 80);

// Start in blocking mode for initial data
socket_set_blocking($socket, true);
$data = socket_read($socket, 1024);

// Switch to non-blocking for subsequent reads
socket_set_blocking($socket, false);

while (true) {
    $more = socket_read($socket, 1024);
    if ($more === false) break;
    $data .= $more;
}

echo "Received data: " . strlen($data) . " bytes\n";
socket_close($socket);

这在初始数据使用阻塞模式,然后切换到非阻塞模式。这种方法结合了两种模式以实现灵活的网络通信。

阻塞套接字的超时处理

本示例展示了如何使用阻塞套接字实现超时。

timeout_handling.php
<?php

declare(strict_types=1);

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_blocking($socket, true);

// Set timeout options
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, [
    "sec" => 5,
    "usec" => 0
]);

$connected = socket_connect($socket, 'example.com', 80);
if ($connected === false) {
    die("Connection failed");
}

$data = socket_read($socket, 1024);
if ($data === false) {
    die("Read timed out after 5 seconds");
}

echo "Received data: $data\n";
socket_close($socket);

即使在阻塞模式下,也可以使用套接字选项设置超时。这可以防止无限等待,同时保持阻塞模式的简单性。

非阻塞套接字服务器

本示例创建了一个简单的非阻塞套接字服务器。

non_blocking_server.php
<?php

declare(strict_types=1);

$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($server, '0.0.0.0', 8080);
socket_listen($server);

// Set server socket to non-blocking
socket_set_blocking($server, false);

echo "Server running on port 8080 (non-blocking)\n";

while (true) {
    $client = socket_accept($server);
    if ($client === false) {
        usleep(100000); // Sleep to prevent CPU overload
        continue;
    }
    
    $data = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!";
    socket_write($client, $data);
    socket_close($client);
}

非阻塞服务器在不等待的情况下检查连接。当没有可用连接时,它会短暂休眠以减少 CPU 使用率。

最佳实践

来源

PHP socket_set_blocking 文档

本教程通过针对不同网络编程场景的实际示例,介绍了 PHP socket_set_blocking 函数。

作者

我叫 Jan Bodnar,是一名充满热情的程序员,拥有丰富的编程经验。我自 2007 年开始撰写编程文章,迄今为止已发表了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有超过十年的经验。

列出 所有 PHP 网络函数