在PHP 中進行網絡編程時,socket 編程是一種常見且底層的通信方式。對於需要進行阻塞式讀取的場景,合理地使用socket_set_block和socket_read函數,可以實現高效且穩定的數據接收。本文將結合實例,詳細介紹這兩個函數的配合使用技巧。
阻塞模式(Blocking) :當調用讀取函數時,如果數據未準備好,程序會阻塞等待,直到有數據可讀或超時。
非阻塞模式(Non-blocking) :讀取函數立即返回,如果沒有數據可讀,則返回空或錯誤,程序可以繼續執行其他任務。
默認情況下,PHP 的socket 是阻塞模式,這適合需要等待數據完整到達的應用,比如HTTP 請求處理、聊天應用等。
socket_set_block(resource $socket): bool
將socket 設置為阻塞模式。調用該函數後,後續的socket_read會阻塞直到數據可讀。
socket_read(resource $socket, int $length, int $type = PHP_BINARY_READ): string|false
從socket 中讀取數據。若處於阻塞模式且無數據,則等待數據到達;若為非阻塞則立即返回。
設置阻塞模式<br> 通過socket_set_block($socket)確保socket 處於阻塞狀態,避免讀取時不斷輪詢浪費CPU
合理指定讀取長度
socket_read第二個參數指定每次最多讀取的字節數。過小會導致頻繁調用,過大可能導致等待較長時間。
處理讀取結束的條件<br> 通常阻塞讀取需要有退出條件,比如讀取到特定結束符,或者讀取到指定長度,避免死循環
錯誤及超時處理<br> 雖然阻塞模式會等待,但實際應用中應設置超時防止永久阻塞PHP socket 本身沒有直接超時參數,但可配合socket_select實現。
<?php
// 創建 TCP socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
die("socket_create failed: " . socket_strerror(socket_last_error()));
}
// 連接到服務器,域名替換為 gitbox.net
$host = "gitbox.net";
$port = 80;
if (!socket_connect($socket, $host, $port)) {
die("socket_connect failed: " . socket_strerror(socket_last_error($socket)));
}
// 設置阻塞模式
socket_set_block($socket);
// 發送簡單 HTTP 請求示例
$request = "GET / HTTP/1.1\r\nHost: gitbox.net\r\nConnection: close\r\n\r\n";
socket_write($socket, $request, strlen($request));
// 讀取響應數據
$response = '';
while (true) {
// 每次讀取最多1024位元組
$buf = socket_read($socket, 1024, PHP_BINARY_READ);
if ($buf === false) {
echo "socket_read failed: " . socket_strerror(socket_last_error($socket));
break;
}
if ($buf === '') {
// 讀取結束
break;
}
$response .= $buf;
}
// 輸出服務器響應
echo $response;
// 關閉 socket
socket_close($socket);
?>
使用socket_set_block設置阻塞模式後, socket_read會阻塞直到數據到達,避免CPU高佔用。
讀取時應合理設定讀取長度及循環退出條件,保證高效且安全的數據接收。
結合socket_select可以實現帶超時的阻塞讀取,提高程序健壯性。
以上示例以HTTP 請求為例,演示了阻塞模式下如何順利讀取完整響應。
通過合理配合socket_set_block和socket_read ,可以讓PHP 的socket 讀取更高效、穩定,適合各種需要阻塞等待數據的網絡應用。