PHP 中的 socket_set_blocking 函数用来设置一个 socket 资源的阻塞模式:
阻塞模式(blocking):调用 socket 相关函数时会等待操作完成,期间程序会停顿。
非阻塞模式(non-blocking):调用 socket 相关函数时立即返回,不会等待操作完成。
默认情况下,socket 是阻塞的。阻塞模式适合简单同步场景,但对于高性能服务器,需要更细致的控制流机制。
bool socket_set_blocking ( resource $socket , bool $mode )
$socket:socket 资源。
$mode:true 表示阻塞,false 表示非阻塞。
控制流即对消息的发送与接收节奏进行管理,防止消息发送过快导致网络拥堵、资源占用过高或消息丢失。带有控制流的设计可以实现:
队列消息缓冲,逐步发送。
动态切换阻塞与非阻塞模式。
超时处理和错误重试机制。
服务器和客户端均使用阻塞模式,保证发送和接收的稳定性。
对消息发送进行队列化,只有发送缓冲区有数据时才发送,防止阻塞等待。
接收端设置合理的超时,避免长时间挂起。
利用 socket_select 实现多路复用,监控读写事件,提升效率。
下面是一个简化的基于 TCP 的 PHP socket 服务端示例,演示了如何用 socket_set_blocking 控制阻塞模式,实现消息收发的流控:
<?php
$host = "0.0.0.0";
$port = 12345;
// 创建socket
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($sock, $host, $port);
socket_listen($sock);
echo "Server started at $host:$port\n";
// 设置监听socket为阻塞模式,接受连接时等待客户端
socket_set_blocking($sock, true);
$clients = [];
while (true) {
// 使用 socket_select 监听活动连接
$read = $clients;
$read[] = $sock; // 加入监听socket
$write = [];
$except = null;
// 阻塞等待活动socket
if (socket_select($read, $write, $except, 5) < 1) {
continue; // 超时无活动
}
// 处理新连接
if (in_array($sock, $read)) {
$newClient = socket_accept($sock);
if ($newClient !== false) {
socket_set_blocking($newClient, true); // 设置客户端socket为阻塞,保证消息完整
$clients[] = $newClient;
echo "New client connected\n";
}
unset($read[array_search($sock, $read)]);
}
// 处理已有客户端消息
foreach ($read as $client) {
$data = socket_read($client, 2048, PHP_NORMAL_READ);
if ($data === false || $data === '') {
// 客户端断开连接
echo "Client disconnected\n";
socket_close($client);
unset($clients[array_search($client, $clients)]);
continue;
}
$data = trim($data);
echo "Received: $data\n";
// 简单回显,带流控:发送前确保socket阻塞模式,防止写入失败
socket_set_blocking($client, true);
$sendResult = socket_write($client, "Echo: $data\n");
if ($sendResult === false) {
echo "Failed to send message to client\n";
}
}
}
阻塞模式的切换
监听 socket 和客户端 socket 都设为阻塞,这样在读取和写入数据时,可以保证数据的完整性,避免因非阻塞模式下的短读短写导致消息不完整。
socket_select 监听多路复用
socket_select 阻塞等待某个 socket 可读,提高 CPU 利用率,避免死循环浪费资源。
消息队列控制(可扩展)
示例中虽然直接读写,但可根据需求添加消息队列,控制每次发送的消息大小和频率,避免客户端网络拥塞。
使用非阻塞模式配合事件驱动库(如 libevent),提升高并发性能。
引入消息序列号、确认机制,保障消息传输完整性。
实现心跳包检测连接状态。
使用 socket_set_option 优化 TCP 参数,如设置 TCP_NODELAY 以减少延迟。
通过合理运用 PHP 的 socket_set_blocking 函数,结合 socket_select 事件监听机制,能够构建一个带有控制流的高效消息收发系统。控制流不仅保证了消息传输的稳定性,还提升了系统的响应速度与资源利用率。希望本文示例和思路对你搭建自己的消息系统有所帮助。