socket_recv

(PHP 4 >= 4.1.0, PHP 5)

socket_recvПолучает данные из подсоединённого сокета

Описание

int socket_recv ( resource $socket , string &$buf , int $len , int $flags )

Функция socket_recv() получает len байт данных в буфер buf из сокета socket. функция socket_recv() может быть использована для получения данных из подсоединённых сокетов. Дополнительно к этому, один или более флагов могут быть указаны для изменения поведения функции.

Параметр buf передаётся по ссылке, так что он должен быть указан в виде переменной в списке аргументов. Данные, прочитанные из сокета socket функцией socket_recv(), будут возвращены в параметре buf.

Список параметров

socket

Параметр socket должен быть ресурсом сокета, предварительно созданным при помощи функции socket_create().

buf

Полученные данные будут переданы в переменную, указанную в параметре buf. Если происходит ошибка, если соединение сброшено, или если данные недоступны, параметр buf будет установлен в NULL.

len

До len байт будет получено с удалённого хоста.

flags

Значение параметра flags может быть любой комбинацией следующих флагов, соединённых при помощи двоичного оператора OR (|).

Possible values for flags
Флаг Описание
MSG_OOB Обрабатывать внеполосные (out-of-band) данные.
MSG_PEEK Получать данные с начала очереди получения без удаления их из очереди.
MSG_WAITALL Функция будет блокировать выполнение скрипта до тех пор, пока как минимум len байт не будет получено. Однако, в том случае, если получен сигнал или удалённый хост отсоединился, функция может вернуть меньше данных.
MSG_DONTWAIT Если этот флаг установлен, то функция вернётся даже в том случае, если бы она обычно блокировала исполнение скрипта.

Возвращаемые значения

socket_recv() возвращает количество полученных байтов, или FALSE в случае ошибки. Фактический код ошибки может быть получен при помощи функции socket_last_error(). Этот код ошибки может быть передан функции socket_strerror() для получения текстового описания ошибки.

Примеры

Пример #1 Пример использования socket_recv()

Этот пример - просто вариант первого примера из статьи Примеры с использованием socket_recv().

<?php
error_reporting
(E_ALL);

echo 
"<h2>Соединение TCP/IP</h2>\n";

/* Получить порт сервиса WWW. */
$service_port getservbyname('www''tcp');

/* Получить IP-адрес целевого хоста. */
$address gethostbyname('www.example.com');

/* Создать сокет TCP/IP. */
$socket socket_create(AF_INETSOCK_STREAMSOL_TCP);
if (
$socket === false) {
    echo 
"Не удалось выполнить функцию socket_create(): причина: " socket_strerror(socket_last_error()) . "\n";
} else {
    echo 
"OK.\n";
}

echo 
"Попытка соединиться с хостом '$address' по порту '$service_port'...";
$result socket_connect($socket$address$service_port);
if (
$result === false) {
    echo 
"Не получилось выполнить функцию socket_connect().\nПричина: ($result) " socket_strerror(socket_last_error($socket)) . "\n";
} else {
    echo 
"OK.\n";
}

$in "HEAD / HTTP/1.1\r\n";
$in .= "Host: www.example.com\r\n";
$in .= "Connection: Close\r\n\r\n";
$out '';

echo 
"Отправка запроса HTTP HEAD...";
socket_write($socket$instrlen($in));
echo 
"OK.\n";

echo 
"Получение ответа:\n\n";
$buf 'Это мой буфер.';
if (
false !== ($bytes socket_recv($socket$buf2048MSG_WAITALL))) {
    echo 
"Прочитано $bytes байта из функции socket_recv(). Закрываем сокет...";
} else {
    echo 
"Не получилось выполнить socket_recv(); причина: " socket_strerror(socket_last_error($socket)) . "\n";
}
socket_close($socket);

echo 
$buf "\n";
echo 
"OK.\n\n";
?>

Пример выше выведет что-то вроде следующего:

<h2>TCP/IP Connection</h2>
OK.
Попытка соединиться с хостом '208.77.188.166' on port '80'...OK.
Отправка запроса HTTP HEAD...OK.
Получение ответа:

Прочитано 123 байта из функции socket_recv(). Закрываем сокет...HTTP/1.1 200 OK
Date: Mon, 14 Sep 2009 08:56:36 GMT
Server: Apache/2.2.3 (Red Hat)
Last-Modified: Tue, 15 Nov 2005 13:24:10 GMT
ETag: "b80f4-1b6-80bfd280"
Accept-Ranges: bytes
Content-Length: 438
Connection: close
Content-Type: text/html; charset=UTF-8

OK.

Коментарии

in case you want to empty/unset $buffer, but failing to do so, try using 0 as flag.
PHP_NORMAL_READ and PHP_BINARY_READ respectively hold 1 and 2 as value.
2004-04-05 12:35:32
http://php5.kiev.ua/manual/ru/function.socket-recv.html
Автор:
I've used socket_select and socket_recv with a while loop and found myself in trouble when remote side closed connection. The code below produced infinite loop and socket_select returned immediately (which lead to high cpu time consumption).

<?

socket_set_nonblock
($my_socket);
$streams = array($my_socket/*, ... */);

$lastAccess time();
while (
socket_select($streams$write NULL$except NULLSLEEP_TIME_SECONDSSLEEP_TIME_MILLISECONDS) !== FALSE) {
    if (
in_array($my_socket$streams)) {
        while (@
socket_recv($my_socket$data81920)) {
            echo 
$data;
        }
       
$lastAccess time();
    } else {
        if (
time()-$lastAccess LAST_ACCESS_TIMEOUT) {
            break;
        }
    }
   
// ...
   
$streams = array($my_socket/*, ... */);
}

?>

The solution was simple, but quite hard to find because socket_recv is not documented. socket_recv returns FALSE if there is no data and 0 if the socket is widowed (disconnected by remote side). So I had just to check return value of socket_recv. The problem now sounds stupid, but I've spend some time to find it out.
I hope this will save some of somebody's hair ;)
2004-11-05 05:57:32
http://php5.kiev.ua/manual/ru/function.socket-recv.html
To read from socket both on linux and windows OS having  flash as a client I use function bellow. $length is the size of  a chunk, not the max length to read. It will continue reading until EOL char  occures or client disconnects (or in case of error), so it works for bigger packets as well.

     function read($descriptor, $length = 1024) {
            $this->method = "read";
            if(!$client){
                echo("No valid socket descriptor !\n");
                return false;
            }
            $read ='';
        while(($flag=socket_recv($descriptor, $buf, $length,0))>0){
              $asc=ord(substr($buf, -1));
            if ($asc==0) {
                $read.=substr($buf,0,-1);
                break;
            }else{
                $read.=$buf;
            }
        }
           if ($flag<0){
            //error
            return false;
        }elseif ($flag==0){
            //Client disconnected
            return  false;
        }else{
              return $read;
        }

     }
2004-11-30 06:58:28
http://php5.kiev.ua/manual/ru/function.socket-recv.html
Автор:
I'm glad that Bastion left the above post about the mysterious int flag. He just helped to fix a problem that I've spent six hours on. Here's my code:

for($ct=1; $ct<=$numrecs; $ct++) {
     $rec = "";
     $nr=socket_recv($fp,$rec,77,0);
     print "Rec # $ct -->";
         print "$rec";
         print "<br>";
      }

The code is pretty simple, it just loops through all my records and prints them out. All records are 77 bytes and all end with a period. The first 36 records print perfectly then at 37 things go bad. The records start to get offset. The last few characters of the 37th record end up printing on the 38th record. The data on the sending side was perfect, so I knew that the problem was with socked_recv.

After reading the above post I tried changing the int flag. Changing the flag to 2 worked:
$nr=socket_recv($fp,$rec,77,2);

Now everything lines up perfectly. I had always left int flag as 0 since it's undocumented. 

Martin K.
2005-05-05 10:42:43
http://php5.kiev.ua/manual/ru/function.socket-recv.html
Автор:
My last post was incorrect. The int flag set to 2 apparently reset the file position pointer so what I was reading was the first record repeatedly. 

My workaroud ended up being the following:

for($ct=1; $ct<=$numrecs; $ct++) {
    $rec = "";
    $nr=socket_recv($fp,$rec,76,0);
       
    //grab the extra bytes.
    $terminator = "";
    while ($terminator != ".") {
        $nr=socket_recv($fp,$terminator,1,0);
    }
   
     $custarray[]=substr($rec,0,76);         
}

Martin K.
2005-05-06 07:59:51
http://php5.kiev.ua/manual/ru/function.socket-recv.html
It looks like that mysterious flags are just the recv(2) flags passed to your OS syscall and nothing more...

ext/sockets/sockets.c:PHP_FUNCTION(socket_recv)
...
        if ((retval = recv(php_sock->bsd_socket, recv_buf, len, flags)) < 1) {
                efree(recv_buf);
...

for linux you can type `man 2 recv' and you will see complete description of thouse flags.

Sergey S. Kosrtyliov <rathamahata@rathamahata.net>
http://www.rathamahata.net/
2005-08-25 07:44:52
http://php5.kiev.ua/manual/ru/function.socket-recv.html
In PHP version 5.* there is a bug: MSG_DONTWAIT flag is not defined (see https://bugs.php.net/bug.php?id=48326)
2012-03-01 10:50:34
http://php5.kiev.ua/manual/ru/function.socket-recv.html
<?php
$er 
error_reporting(0);
$bytes    socket_recv($socket,$buffer,1,MSG_WAITALL);
error_reporting($er);

// MEGA BUG HERE
// this statuses are wrong and swapped, closed socket must be with "FALSE"
// but in fact he swap the values:
// function.socket-recv
// 
if($bytes===false){ // no data available, socket not closed
   
echo 'WS_READ_ERR1: '.socket_strerror(socket_last_error($socket)).PHP_EOL;
   
// print when no data available:
    // WS_READ_ERR1: Resource temporarily unavailable
   
continue;
}else if(
$bytes===0){ // socket closed
   
echo 'WS_READ_ERR2: '.socket_strerror(socket_last_error($socket)).PHP_EOL;
   
// print when socket closed:
    // WS_READ_ERR2: Success
   
$process->close();
}

?>
2013-07-17 14:09:43
http://php5.kiev.ua/manual/ru/function.socket-recv.html
Workaround for the missing MSG_DONTWAIT flag according to the bug report page:

<?php if(!defined('MSG_DONTWAIT')) define('MSG_DONTWAIT'0x40); ?>
2014-07-14 18:45:57
http://php5.kiev.ua/manual/ru/function.socket-recv.html
socket_recv()
returns FALSE if client returned no data
returns 0 (zero) if client disconnected

also (asuming case socket_select() "gave" us a "changed" socket):
if 
socket_recv() returned FALSE 
and no bytes were received 
then
client "crashed" (call it disconnected).

else if
socket_recv() returned 0 (zero) 
and no bytes were received 
then
client "normaly" disconnected.

Im pretty sure -- 99.99%.
Example:
<?php
function receive($socket)
{
   
// !
    // on all following cases we assume that
    // socket_select() returned the current socket as "changed"
    // !

   
$timeout 3// set your timeout

    /* important */
   
$socket_recv_return_values['no_data_received'] = false;
   
$socket_recv_return_values['client_disconnected'] = 0;

   
$start time();
   
$received_data null;
   
$received_bytes null;
   
socket_set_nonblock($socket);
   
socket_clear_error();
    while(
        (
$t_out=((time()-$start) >= $timeout)) === false
       
and ($read=@socket_recv($socket$buf40960)) >= 1
   
){
       
$received_data  = (isset($received_data)) ? $received_data $buf $buf;
       
$received_bytes = (isset($received_bytes)) ? $received_bytes $read $read;
    }
   
$last_error socket_last_error($socket);
   
socket_set_block($socket);

    if(
$t_out === true){
        throw new 
Exception(
           
'timeout after ' . ((!$received_bytes) ? $received_bytes) . ' bytes',
           
// your eCode here
       
);
    }
    elseif(
$last_error !== false and $last_error !== 0){
        throw new 
Exception(
           
socket_strerror($last_error),
           
$last_error
       
);
    }
    else{
        if(
$read === $socket_recv_return_values['no_data_received']){
           
// client returned NO DATA
            // but we were in a loop and could have got some data before:
           
if($received_bytes 1){
               
// client is connected but sent NO DATA ?
                // no:
                // in this case the client must be "crashed" because -
                // it is not possible to "send no data" (zero bytes)
                // socket_select() now returns this socket as "changed" "forever"
               
throw new Exception(
                   
'client crashed',
                   
// your eCode here
               
);
            }else{
               
// client returned DATA
               
return $received_data;
            }
        }
        elseif(
$read === $socket_recv_return_values['client_disconnected']){
           
// client disconnected
           
if($received_bytes 1){
               
// client disconnected before/without sending any bytes
               
throw new Exception(
                   
'client disconnected',
                   
// your eCode here
               
);
            }
            else{
               
// *this value* ^= $socket_recv_return_values['client_disconnected']
                //
                // client disconnected AFTER sending data (we were in a loop!)
                // socket_select() will return this socket "forever" as "changed" and -
                // socket_recv() will return *this value* "forever".
                // we will be "back" again "very soon" to see:
                //  socket_recv() returns *this value* AND no bytes received
                //  which results in disconnect-exception above
               
return $received_data;
            }
        }
    }
}
?>
2014-10-13 05:17:51
http://php5.kiev.ua/manual/ru/function.socket-recv.html
Usage example for MSG_PEEK: this function tells if the socket has data available to be read, but preserving it to be read at a future moment.

<?php
// Workaround for the missing define
if(!defined('MSG_DONTWAIT')) define('MSG_DONTWAIT'0x40);

// Function to check if there is data available in the socket
function SocketHasData($socket) {
   
// Based on the following fact:
    // $result=0 -> disconnected, $result=false -> no data

   
$data ''// We need a buffer, but we won't use it

    // MSG_PEEK means to preserve data in the queue, so it can
    // actually be read afterwards
   
$result socket_recv($socket$data1MSG_PEEK MSG_DONTWAIT );

    if (
$result === false) return false// If no data, returns false
   
return true// Otherwise returns true
}
?>
2017-07-23 10:39:07
http://php5.kiev.ua/manual/ru/function.socket-recv.html
It seems like the flags are just passed to the underlying recv() function of your OS, hence there no MSG_DONTWAIT flag on Windows and you should not define it yourself in that case, it just won't work.
2018-11-05 20:21:53
http://php5.kiev.ua/manual/ru/function.socket-recv.html
Автор:
<?php

namespace Safe;

use 
Safe\Exceptions\SocketsException;

/**
 * After the socket socket has been created
 * using socket_create, bound to a name with
 * socket_bind, and told to listen for connections
 * with socket_listen, this function will accept
 * incoming connections on that socket. Once a successful connection
 * is made, a new socket resource is returned, which may be used
 * for communication. If there are multiple connections queued on
 * the socket, the first will be used. If there are no pending
 * connections, socket_accept will block until
 * a connection becomes present. If socket
 * has been made non-blocking using
 * socket_set_blocking or
 * socket_set_nonblock, FALSE will be returned.
 *
 * The socket resource returned by
 * socket_accept may not be used to accept new
 * connections. The original listening socket
 * socket, however, remains open and may be
 * reused.
 *
 * @param resource $socket A valid socket resource created with socket_create.
 * @return resource Returns a new socket resource on success. The actual
 * error code can be retrieved by calling
 * socket_last_error. This error code may be passed to
 * socket_strerror to get a textual explanation of the
 * error.
 * @throws SocketsException
 *
 */
function socket_accept($socket)
{
   
error_clear_last();
   
$result \socket_accept($socket);
    if (
$result === false) {
        throw 
SocketsException::createFromPhpError();
    }
    return 
$result;
}

/**
 * Create a Socket resource, and bind it to the provided AddrInfo resource.  The return
 * value of this function may be used with socket_listen.
 *
 * @param resource $addr Resource created from socket_addrinfo_lookup.
 * @return resource Returns a Socket resource on success.
 * @throws SocketsException
 *
 */
function socket_addrinfo_bind($addr)
{
   
error_clear_last();
   
$result \socket_addrinfo_bind($addr);
    if (
$result === null) {
        throw 
SocketsException::createFromPhpError();
    }
    return 
$result;
}
2021-03-10 11:49:31
http://php5.kiev.ua/manual/ru/function.socket-recv.html

    Поддержать сайт на родительском проекте КГБ