從 PHP 原始碼層面分析 socket_read() 與 socket_recv() 的本質差異:前者支援 PHP_NORMAL_READ 模式逐行讀取,後者直接封裝系統 recv() 呼叫。
string socket_read (resource $socket, int $length [, int $type = PHP_BINARY_READ])
int socket_recv (resource $socket, string &$buf, int $len, int $flags)
socket_read:回傳資料,支援 type 參數切換模式socket_recv:透過引用 &$buf 回傳資料,回傳值為接收位元組數,支援 flags核心一行呼叫系統 recv():
if ((retval = recv(php_sock->bsd_socket, recv_buf, len, flags)) < 1) {
其餘為參數解析、記憶體配置、zval 重建等 PHP 內部處理。
當 type == PHP_NORMAL_READ 時,呼叫內部 php_read() 而非 recv():
if (type == PHP_NORMAL_READ) {
retval = php_read(php_sock, tmpbuf, length, 0);
} else {
retval = recv(php_sock->bsd_socket, tmpbuf, length, 0);
}
循環呼叫 recv() 每次 1 位元組,直到遇到 \n 或 \r 或達 maxlen:
while (*t != '\n' && *t != '\r' && n < maxlen) {
m = recv(sock->bsd_socket, (void *) t, 1, flags);
// ... 錯誤處理與非阻塞判斷
}
| 場景 | 建議函數 | 原因 |
|---|---|---|
| 二進位資料、固定長度讀取 | socket_recv / socket_read(PHP_BINARY_READ) | 直接對應系統 recv,效能最佳 |
| 文字協定、按行讀取(HTTP、SMTP 等) | socket_read(PHP_NORMAL_READ) | 內建換行符偵測,避免自行緩衝解析 |
| 需控制 flags(MSG_PEEK、MSG_WAITALL 等) | socket_recv | 唯一支援 flags 參數 |