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";
}
}
}
阻塞模式的切換<br> 監聽socket 和客戶端socket 都設為阻塞,這樣在讀取和寫入數據時,可以保證數據的完整性,避免因非阻塞模式下的短讀短寫導致消息不完整
socket_select 監聽多路復用
socket_select阻塞等待某個socket 可讀,提高CPU 利用率,避免死循環浪費資源。
消息隊列控制(可擴展)
示例中雖然直接讀寫,但可根據需求添加消息隊列,控制每次發送的消息大小和頻率,避免客戶端網絡擁塞。
使用非阻塞模式配合事件驅動庫(如libevent),提升高並發性能。
引入消息序列號、確認機制,保障消息傳輸完整性。
實現心跳包檢測連接狀態。
使用socket_set_option優化TCP 參數,如設置TCP_NODELAY 以減少延遲。
通過合理運用PHP 的socket_set_blocking函數,結合socket_select事件監聽機制,能夠構建一個帶有控制流的高效消息收發系統。控制流不僅保證了消息傳輸的穩定性,還提升了系統的響應速度與資源利用率。希望本文示例和思路對你搭建自己的消息系統有所幫助。