CakeFest 2024: The Official CakePHP Conference

stream_socket_recvfrom

(PHP 5, PHP 7, PHP 8)

stream_socket_recvfrom接続されているかどうかにかかわらず、ソケットからのデータを受信する

説明

stream_socket_recvfrom(
    resource $socket,
    int $length,
    int $flags = 0,
    ?string &$address = null
): string|false

stream_socket_recvfrom() は、 リモートソケットから最大 length バイトのデータを 受け取ります。

パラメータ

socket

リモートソケット。

length

socket から受信するバイト数。

flags

flags は以下の値の組み合わせです。

flags でとりうる値
STREAM_OOB OOB (out-of-band) データを処理します。
STREAM_PEEK ソケットからデータを取得しますが、バッファを消費しません。 fread() あるいは stream_socket_recvfrom() を続けてコールした 際には、同じデータが読み込まれます。

address

address が指定された場合、 そこにはリモートソケットのアドレスが保存されます。

戻り値

読み込んだデータを文字列で返します。 失敗した場合に false を返します

例1 stream_socket_recvfrom() の例

<?php
/* localhost のポート 1234 へのサーバーソケットをオープンします */
$server = stream_socket_server('tcp://127.0.0.1:1234');

/* 接続を受け付けます */
$socket = stream_socket_accept($server);

/* OOB データのパケットを取得します(1500 は典型的な MTU のサイズです) */
echo "Received Out-Of-Band: '" . stream_socket_recvfrom($socket, 1500, STREAM_OOB) . "'\n";

/* 通常の帯域内のデータを読み込みますが、バッファを消費しません */
echo "Data: '" . stream_socket_recvfrom($socket, 1500, STREAM_PEEK) . "'\n";

/* 同じパケットをもう一度読み込みます。今度はバッファからそれを削除します */
echo "Data: '" . stream_socket_recvfrom($socket, 1500) . "'\n";

/* ソケットを閉じます */
fclose($socket);
fclose($server);
?>

注意

注意:

受信したメッセージが length パラメータより 長かった場合、ソケットの型によっては(例えば UDP など)超過分の バイトデータが捨てられてしまう可能性があります。

注意:

バッファベースのストリーム関数 (fread() あるいは stream_get_line() など) をコールした後に ソケットベースのストリームで stream_socket_recvfrom() をコールすると、ストリームバッファを経由せず、データをソケットから 直接読み込みます。

参考

  • stream_socket_sendto() - 接続されているかどうかにかかわらず、ソケットにデータを送信する
  • stream_socket_client() - インターネットドメインまたは Unix ドメインのソケット接続を開く
  • stream_socket_server() - インターネットドメインまたは Unix ドメインのサーバーソケットを作成する
add a note

User Contributed Notes 3 notes

up
23
cweiske at php dot net
14 years ago
Note that stream_socket_recvfrom() bypasses stream wrappers including TLS/SSL. While reading from an encrypted stream with fread() will return decrypted data, using stream_socket_recvfrom() will give you the original encrypted bytes.
up
6
MagicalTux at php dot net
13 years ago
This method may return a peer address not compatible with stream_socket_sendto() if in ipv6.

The ip returned by recvfrom is not within brackets ([]), and has the port appended, which makes it look like ::1:1234. To cut it properly, use strrpos()
up
2
raat1979 at gmail dot com
8 years ago
Basically there is currently no real way to determine what the position of the Out of band data is in the tcp/ip stream.

However, it seems that In my current environment (winsock: Windows / PHP 5.3.0) you do not peek beyond the OOB byte unless the buffer is empty
reads do read beyond the OOB data. (I'll check my linux box later)

You should be able to figure out the position of the OOB data by peeking and reading from the regular stream
although it would not be 100% reliable as we do read beyond the OOB data when nothing is in front of it.
depending on the high level protocol it might be possible
to handle the specific "no data in front of out-of-band data" case

<?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
To Top