Pay attention! On some PHP version the MSG_DONTWAIT flag is not defined (see https://bugs.php.net/bug.php?id=48326)
socket_recvfrom
(PHP 4 >= 4.1.0, PHP 5)
socket_recvfrom — 接続しているかどうかによらず、ソケットからデータを受信する
説明
$socket
, string &$buf
, int $len
, int $flags
, string &$name
[, int &$port
] )
socket_recvfrom() 関数は、
ポート port (AF_UNIX
型のソケットである場合を除く) 上の name
から受信した len バイトのデータを
buf に格納します。
socket_recvfrom() は、
接続済みのソケットだけでなく接続していないソケットに対しても使用可能です。
さらに、フラグを指定することでこの関数の挙動を設定できます。
name と port
は参照渡しとしなければなりません。接続していないソケットの場合は、
name はリモートホストの IP アドレスか
UNIX ソケットへのパスとなります。接続済みのソケットの場合は、
name は NULL とします。
また、AF_INET あるいは
AF_INET6 形式のまだ接続していないソケットの場合、
port にはリモートホストのポート番号を指定します。
パラメータ
-
socket -
socketには、 socket_create() で作成したソケットリソースを指定します。 -
buf -
受信したデータが
bufに格納されます。 -
len -
最大
lenバイトまでのデータをリモートホストから取得します。 -
flags -
flagsの値は、以下のフラグの任意の組み合わせを 論理 OR 演算子 (|) で連結したものとなります。flagsに使用できる値フラグ 説明 MSG_OOB帯域外 (out-of-band) のデータを処理する。 MSG_PEEK受信キューの先頭にあるデータを受信し、 そのデータをそのままキューに残しておく。 MSG_WAITALL少なくとも lenバイト受信するまではブロックする。 しかし、もし何らかのシグナルを受信したりリモートホストとの接続が切断された場合は これより少ないバイト数を返す可能性がある。MSG_DONTWAIT通常はブロックする場面であってもそのまま return する。 -
name -
AF_UNIX型のソケットの場合は、nameはファイルへのパスとなります。 それ以外の場合は、未接続のソケットの場合にはnameはリモートホストの IP アドレスとなります。 接続済みソケットの場合はNULLとなります。 -
port -
この引数は
AF_INET型あるいはAF_INET6型のソケットに対してのみ適用され、 データを受信するリモートホストのポートを指定します。 接続済みソケットの場合はportはNULLとなります。
返り値
socket_recvfrom() は、受信したバイト数を返します。
あるいはエラー時には FALSE を返します。
エラーコードを取得するには socket_last_error()
をコールします。取得したエラーコードを
socket_strerror() に渡すと、
そのエラーについての説明を得ることができます。
例
例1 socket_recvfrom() の例
<?php
error_reporting(E_ALL | E_STRICT);
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($socket, '127.0.0.1', 1223);
$from = '';
$port = 0;
socket_recvfrom($socket, $buf, 12, 0, $from, $port);
echo "リモートアドレス $from のポート $port から $buf を受信しました" . PHP_EOL;
?>
この例は、127.0.0.1 のポート 1223 との UDP ソケットを確立し、受信したデータを最大 12 バイトまで表示します。
変更履歴
| バージョン | 説明 |
|---|---|
| 4.3.0 | socket_recvfrom() はバイナリセーフとなりました。 |
参考
- socket_recv() - 接続したソケットからデータを受信する
- socket_send() - 接続したソケットにデータを送信する
- socket_sendto() - 接続しているかどうかによらずソケットにメッセージを送信する
- socket_create() - ソケット(通信時の終端)を作成する
I said in my previous note that I'd add a secondary post when I found out more about how to use socket_recvfrom(). So here it is.
As I suspected, the example given is dead-flat-wrong and should be avoided. You WILL need to use pointers like the description at the top of the page says. My working socket_recvfrom() command looks like this:
$bytes = socket_recvfrom ($socket, &$udp_reply, 100, 0, &$from_addr, &$from_port);
Also, even if you have no interest in the the information at all, you must create the $from_addr and $from_port variables and pass them by reference. PHP doesn't support passing in NULL just because you might not give a rat's patootie about the information.... ;)
R.
The example doesn't match the format described at the top of the page. It appears to me that to use this command to receive UDP data, I need to format my calling parameter as follows:
int socket_recvfrom
(
resource $socket, // Created this with socket_create
string &$buf, // This is a pointer!!
int $len, // I know the amount of data
int $flags, // I know the flags I want
string &$name, // This is ALSO a pointer!
int &$port // This is ALSO a pointer, TOO!!
);
The example doesn't use any pointers, just values, and I didn't think socket_bind was necessary for UDP sockets. At least, it isn't in C. Anybody got a example that does work?? (Because this doesn't see to so far.)
If I do stumble on a combination of settings that works, I'll post it -- but this doesn't seem to be the most active page on PHP.net....
R.
I'm confused about the rerturn value of socket_recvfrom(), it said -1 when failed, but when I call like this:
if (($len = @socket_recvfrom($sock, $result, 32, 0, $ip, $port)) == -1) {
if ($this->_debug) {
echo "socket_read() failed: " . socket_strerror(socket_last_error()) . "\n";
}
return false;
}
variable $len = false, when I change the buffer length from 32 to 4096, it becomes right.
DNS RELAY USING UDP SOCKETS
<?php
while(TRUE) {
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
if($socket === FALSE)
{
echo 'Socket_create failed: '.socket_strerror(socket_last_error())."\n";
}
if(!socket_bind($socketD, "0.0.0.0", 53)) {
socket_close($socketD);
echo 'socket_bind failed: '.socket_strerror(socket_last_error())."\n";
}
socket_recvfrom($socket,$buf,65535,0,$clientIP,$clientPort);
$stz = bin2hex($buf);
$tx = "";
for($i=0;$i<(strlen($stz)-26-10)/2;$i++)
{
$e = "00";
$e[0] = $stz[$i*2+26];
$e[1] = $stz[$i*2+27];
$f = hexdec($e);
if($f > 0 && $f < 32) $tx .= "."; else
$tx .= sprintf("%c",$f);
}
echo "$clientIP <".$tx.">\n";
$fp = fsockopen("udp://72.174.110.4",53,$errno,$errstr);
if (!$fp)
{
echo "ERROR: $errno - $errstr<br />\n";
}
else
{
fwrite($fp,$buf);
$ret = $buf;
$ret = fread($fp,667);
fclose($fp);
}
}
socket_send($socket,$ret,667,0);
}
?>
This function is very handy when dealing with UDP connections, because it enables you to know who's the client who connected to your socket. Bear in mind that UDP doesn't care about the source of the connection, the packets may be annonymous or even faked. No check is required.
If you want to listen on an UDP socket and answer to the client, read my comment on socket_listen() -> http://www.php.net/manual/en/function.socket-listen.php
