<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>