阻塞式接收指的是当程序调用接收函数时,如果接收缓冲区没有数据,程序会暂停执行,等待数据到达后才继续执行。这样可以保证接收到的数据是完整且实时的,但如果网络状况不好,程序可能会长时间等待。
PHP默认的socket就是阻塞模式,如果使用 socket_set_nonblock 将其设置为非阻塞,socket_recv 在没有数据时会立即返回。
socket_set_block(resource $socket): bool
将指定的socket设置为阻塞模式。
socket_recv(resource $socket, string &$buf, int $len, int $flags): int|false
从socket接收数据。阻塞模式下,如果无数据,程序会等待数据到来。
下面的示例演示如何创建一个TCP客户端,连接到服务器后,使用 socket_set_block 将socket设置为阻塞模式,然后使用 socket_recv 阻塞式地接收数据。
<?php
// 创建TCP socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
die("socket_create failed: " . socket_strerror(socket_last_error()) . "\n");
}
// 连接到服务器
$server_ip = 'gitbox.net';
$server_port = 8080;
$result = socket_connect($socket, $server_ip, $server_port);
if ($result === false) {
die("socket_connect failed: " . socket_strerror(socket_last_error($socket)) . "\n");
}
// 设置socket为阻塞模式(默认其实已经是阻塞)
socket_set_block($socket);
echo "连接成功,等待接收数据...\n";
while (true) {
$buffer = '';
// 从socket阻塞接收最多1024字节
$bytes = socket_recv($socket, $buffer, 1024, 0);
if ($bytes === false) {
echo "socket_recv failed: " . socket_strerror(socket_last_error($socket)) . "\n";
break;
} elseif ($bytes === 0) {
// 连接关闭
echo "服务器关闭连接\n";
break;
} else {
echo "接收到 {$bytes} 字节数据: $buffer\n";
}
}
// 关闭socket
socket_close($socket);
?>
创建TCP socket。
连接到指定服务器(域名用gitbox.net代替)。
调用 socket_set_block,确保socket是阻塞状态。
调用 socket_recv,如果当前没有数据,会阻塞等待直到有数据可读。
接收到数据后打印输出。
如果服务器关闭连接,退出循环,关闭socket。
socket_set_block 可以显式设置socket为阻塞模式,保证调用 socket_recv 时阻塞等待数据。
阻塞模式适合对数据实时性要求高且不介意等待的场景。
如果希望程序不阻塞,可以使用 socket_set_nonblock 或设置socket超时。
理解阻塞和非阻塞机制,有助于更灵活地设计网络通信程序,满足不同应用需求。