阻塞式接收指的是當程序調用接收函數時,如果接收緩衝區沒有數據,程序會暫停執行,等待數據到達後才繼續執行。這樣可以保證接收到的數據是完整且實時的,但如果網絡狀況不好,程序可能會長時間等待。
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超時。
理解阻塞和非阻塞機制,有助於更靈活地設計網絡通信程序,滿足不同應用需求。