请注意,stream_socket_recvfrom() 会绕过流包装器,包括 TLS/SSL。虽然从加密流使用 fread() 读取将返回解密数据,但使用 stream_socket_recvfrom() 会得到原始加密字节。
(PHP 5, PHP 7, PHP 8)
stream_socket_recvfrom — 从连接或未连接的套接字接收数据
stream_socket_recvfrom() 从远程套接字接受数据,最多 length
字节。
socket
远程套接字。
length
要从 socket
接收的字节数。
flags
flags
的值可以是以下任何组合
STREAM_OOB |
处理 OOB (out-of-band ) 数据。 |
STREAM_PEEK |
从套接字检索数据,但不消耗缓冲区。后续对 fread() 或 stream_socket_recvfrom() 的调用将看到相同的数据。 |
address
如果提供了 address
,它将被填充为远程套接字的地址。
返回读取的数据,以字符串形式,或在失败时返回 false
。
示例 #1 stream_socket_recvfrom() 示例
<?php
/* 在本地主机上打开一个到端口 1234 的服务器套接字 */
$server = stream_socket_server('tcp://127.0.0.1:1234');
/* 接受连接 */
$socket = stream_socket_accept($server);
/* 获取一个 OOB 数据包(1500 是一个典型的 MTU 大小) */
echo "接收到的带外数据: '" . stream_socket_recvfrom($socket, 1500, STREAM_OOB) . "'\n";
/* 窥视正常的带内数据,但不要消耗它。 */
echo "数据: '" . stream_socket_recvfrom($socket, 1500, STREAM_PEEK) . "'\n";
/* 再次获取完全相同的数据包,但这次将其从缓冲区中删除。 */
echo "数据: '" . stream_socket_recvfrom($socket, 1500) . "'\n";
/* 关闭它 */
fclose($socket);
fclose($server);
?>
注意:
如果接收到的消息长度超过
length
参数,则可能会丢弃多余的字节,具体取决于接收消息的套接字类型(例如 UDP)。
注意:
在基于套接字的流上调用 stream_socket_recvfrom() 时,在调用基于缓冲区的流函数(如 fread() 或 stream_get_line())之后,会直接从套接字读取数据,绕过流缓冲区。
请注意,stream_socket_recvfrom() 会绕过流包装器,包括 TLS/SSL。虽然从加密流使用 fread() 读取将返回解密数据,但使用 stream_socket_recvfrom() 会得到原始加密字节。
如果在 ipv6 中,此方法可能会返回与 stream_socket_sendto() 不兼容的对等地址。
recvfrom 返回的 ip 没有在括号 ([]) 内,并且附加了端口,这使得它看起来像 ::1:1234。要正确地截断它,请使用 strrpos()
基本上,目前还没有真正的方法来确定带外数据的在 tcp/ip 流中的位置。
但是,在我的当前环境(winsock: Windows / PHP 5.3.0)中,似乎除非缓冲区为空,否则您不会窥视带外字节。
读取确实会读取带外数据之外的数据。(我稍后会检查我的 Linux 机器)
您可以通过窥视和从常规流读取来确定带外数据的的位置。
虽然它不会 100% 可靠,因为当带外数据前面没有数据时,我们确实会读取带外数据之外的数据。
根据高级协议,它可能是可能的。
处理特定的“带外数据前面没有数据”情况
<?php
echo "<pre>";
$sockets = stream_socket_pair(STREAM_PF_INET, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
$reader=$sockets[0];
$writer=$sockets[1];
stream_socket_sendto($writer,"abc");
stream_socket_sendto($writer,"xyZ",STREAM_OOB); // ONLY THE LAST BYTE IS MARKED AS OOB DATA
stream_socket_sendto($writer,"def");
echo "\r\n";
echo "Test 1, Peeking beyond oob when the read buffer becomes empty\r\n";
echo "The data order is 'abcxyZdef'\r\n";
stream_select($r=array($reader), $w=array(), $x=array($reader),5);
echo "has regular:";var_dump(count($r)!==0);
echo "has oobData:";var_dump(count($x)!==0);
echo "<span style='color:blue' >Peek (9) regular:".stream_socket_recvfrom($reader,9,STREAM_PEEK)."</span>\r\n";
echo "<span style='color:green'>Peek (1) OobData:".stream_socket_recvfrom($reader,9,STREAM_OOB|STREAM_PEEK)."</span>\r\n";
echo "<span style='color:black'>READ (4) regular:".stream_socket_recvfrom($reader,4)."</span>\r\n";
echo "<span style='color:blue' >Peek (9) regular:".stream_socket_recvfrom($reader,9,STREAM_PEEK)."</span>\r\n";
echo "<span style='color:black'>READ (1) regular:".stream_socket_recvfrom($reader,1)."</span>\r\n";
echo "<span style='color:blue' >Peek (9) regular:".stream_socket_recvfrom($reader,9,STREAM_PEEK)."</span>\r\n";
// read the OOB data
echo "<span style='color:red' >READ (9) OobData:".stream_socket_recvfrom($reader,9,STREAM_OOB)."</span>\r\n";
echo "<span style='color:blue' >Peek (9) regular:".stream_socket_recvfrom($reader,9,STREAM_PEEK)."</span>\r\n";
fclose($sockets[0]);
fclose($sockets[1]);
echo "</pre>";
?>
outputs
Test 1, Peeking beyond oob when the read buffer becomes empty
The data order is 'abcxyZdef'
has regular:bool(true)
has oobData:bool(true)
Peek (9) regular:abcxy
Peek (1) OobData:Z
READ (4) regular:abcx
Peek (9) regular:y
READ (1) regular:y
Peek (9) regular:def
READ (9) OobData:Z
Peek (9) regular:def
<?php
echo "<pre>";
$sockets = stream_socket_pair(STREAM_PF_INET, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
$reader=$sockets[0];
$writer=$sockets[1];
stream_socket_sendto($writer,"Z",STREAM_OOB); // ONLY THE LAST BYTE IS MARKED AS OOB DATA
stream_socket_sendto($writer,"abcxydef");
echo "<hr/>";
echo "\r\n";
echo "Test 2, peek if there is nothing in front of the OOB data\r\n";
echo "The data order is 'Zabcxydef'\r\n";
stream_select($r=array($reader), $w=array(), $x=array($reader),5);
echo "has regular:";var_dump(count($r)!==0);
echo "has oobData:";var_dump(count($x)!==0);
echo "<span style='color:blue'>peek (9) regular:".stream_socket_recvfrom($reader,9,STREAM_PEEK)."</span>\r\n";
echo "<span style='color:red' >Peek (9) OobData:".stream_socket_recvfrom($reader,9,STREAM_OOB)."</span>\r\n";
echo "<span style='color:blue'>peek (9) regular:".stream_socket_recvfrom($reader,9,STREAM_PEEK)."</span>\r\n";
echo "</pre>";
?>
Outputs
Test 2, peek if there is nothing in front of the OOB data
The data order is 'Zabcxydef'
has regular:bool(true)
has oobData:bool(true)
peek (9) regular:abcxydef
Peek (9) OobData:Z
peek (9) regular:abcxydef