<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-comment">// 以下内容与文章正文无关</span></span><span>
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"这是一段示例 PHP 代码,用于展示与文章无关的前置部分。\n"</span></span><span>;
-------------------------------------------------------------------------------
<span class="hljs-comment">/**
* 如何通过 stream_set_blocking 控制 PHP 中套接字的读取行为,提升网络应用性能?
*
* 在 PHP 网络编程中,套接字(socket)的读取行为对应用性能有直接影响。默认情况下,
* PHP 的套接字操作是阻塞式的,即当调用读取函数(如 fread 或 stream_get_contents)时,
* 如果没有数据到达,程序会一直等待,直到数据可用。这种行为在高并发或长连接场景下容易导致性能瓶颈。
*
* 为了解决这一问题,PHP 提供了 stream_set_blocking 函数,可以灵活地控制套接字的阻塞模式。
*
* 一、stream_set_blocking 的基本用法
*
* 函数原型:
* bool stream_set_blocking ( resource $stream , int $mode )
*
* 参数说明:
* - $stream: 套接字资源(stream 资源)。
* - $mode: 阻塞模式,1 表示阻塞(blocking),0 表示非阻塞(non-blocking)。
*
* 示例:
*/</span>
</span><span><span class="hljs-variable">$socket</span></span><span> = </span><span><span class="hljs-title function_ invoke__">stream_socket_client</span></span><span>(</span><span><span class="hljs-string">"tcp://127.0.0.1:8080"</span></span><span>, </span><span><span class="hljs-variable">$errno</span></span><span>, </span><span><span class="hljs-variable">$errstr</span></span><span>, </span><span><span class="hljs-number">30</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (!</span><span><span class="hljs-variable">$socket</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"连接失败: <span class="hljs-subst">$errstr</span></span></span><span> (</span><span><span class="hljs-subst">$errno</span></span><span>)\n";
} </span><span><span class="hljs-keyword">else</span></span><span> {
</span><span><span class="hljs-comment">// 设置非阻塞模式</span></span><span>
</span><span><span class="hljs-title function_ invoke__">stream_set_blocking</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>, </span><span><span class="hljs-number">0</span></span><span>);
</span><span><span class="hljs-comment">// 尝试读取数据</span></span><span>
</span><span><span class="hljs-variable">$data</span></span><span> = </span><span><span class="hljs-title function_ invoke__">fread</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>, </span><span><span class="hljs-number">8192</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$data</span></span><span> === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"当前没有可读数据,程序继续执行。\n"</span></span><span>;
} </span><span><span class="hljs-keyword">else</span></span><span> {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"读取到数据: <span class="hljs-subst">$data</span></span></span><span>\n";
}
}
-------------------------------------------------------------------------------
<span class="hljs-comment">/**
* 二、阻塞模式与非阻塞模式的差异
*
* 1. 阻塞模式(blocking)
* - fread 或 fgets 会等待数据到达才返回。
* - 适用于单线程、低并发的场景。
* - 简单,但可能导致长时间等待阻塞整个脚本。
*
* 2. 非阻塞模式(non-blocking)
* - fread 等函数立即返回,若无数据则返回空或 false。
* - 适合异步处理、高并发场景。
* - 可以结合 stream_select 监控多个套接字的可读状态,从而提高网络应用性能。
*
* 三、结合 stream_select 提升性能
*
* stream_select 可以监控多个流是否可读、可写或发生异常:
*
* 示例:
*/</span>
</span><span><span class="hljs-variable">$read</span></span><span> = [</span><span><span class="hljs-variable">$socket</span></span><span>];
</span><span><span class="hljs-variable">$write</span></span><span> = </span><span><span class="hljs-literal">null</span></span><span>;
</span><span><span class="hljs-variable">$except</span></span><span> = </span><span><span class="hljs-literal">null</span></span><span>;
</span><span><span class="hljs-variable">$timeout</span></span><span> = </span><span><span class="hljs-number">2</span></span><span>; </span><span><span class="hljs-comment">// 超时时间 2 秒</span></span><span>
</span><span><span class="hljs-variable">$num_changed_streams</span></span><span> = </span><span><span class="hljs-title function_ invoke__">stream_select</span></span><span>(</span><span><span class="hljs-variable">$read</span></span><span>, </span><span><span class="hljs-variable">$write</span></span><span>, </span><span><span class="hljs-variable">$except</span></span><span>, </span><span><span class="hljs-variable">$timeout</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$num_changed_streams</span></span><span> === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"监控套接字出错\n"</span></span><span>;
} </span><span><span class="hljs-keyword">elseif</span></span><span> (</span><span><span class="hljs-variable">$num_changed_streams</span></span><span> === </span><span><span class="hljs-number">0</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"超时,暂无可读数据\n"</span></span><span>;
} </span><span><span class="hljs-keyword">else</span></span><span> {
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$read</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$r</span></span><span>) {
</span><span><span class="hljs-variable">$data</span></span><span> = </span><span><span class="hljs-title function_ invoke__">fread</span></span><span>(</span><span><span class="hljs-variable">$r</span></span><span>, </span><span><span class="hljs-number">8192</span></span><span>);
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"接收到数据: <span class="hljs-subst">$data</span></span></span><span>\n";
}
}
-------------------------------------------------------------------------------
<span class="hljs-comment">/**
* 四、实际应用中的性能优化建议
*
* 1. 在高并发网络应用中,尽量使用非阻塞模式读取套接字,避免单个慢连接阻塞整个进程。
* 2. 使用 stream_select 或类似事件循环机制(如 ReactPHP)来轮询多个套接字。
* 3. 对于长连接,合理设置读取超时时间,避免无限阻塞。
* 4. 避免在阻塞模式下处理大量数据,必要时可分块读取或使用缓冲。
*
* 通过合理使用 stream_set_blocking 和事件循环机制,可以显著提升 PHP 网络应用的响应速度和吞吐量。
*/</span>
</span><span><span class="hljs-meta">?></span></span><span>
</span></span>