PHP Australia Conference 2015

socket_recv

(PHP 4 >= 4.1.0, PHP 5)

socket_recvReceives data from a connected socket

Descrierea

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

The socket_recv() function receives len bytes of data in buf from socket. socket_recv() can be used to gather data from connected sockets. Additionally, one or more flags can be specified to modify the behaviour of the function.

buf is passed by reference, so it must be specified as a variable in the argument list. Data read from socket by socket_recv() will be returned in buf.

Parametri

socket

The socket must be a socket resource previously created by socket_create().

buf

The data received will be fetched to the variable specified with buf. If an error occurs, if the connection is reset, or if no data is available, buf will be set to NULL.

len

Up to len bytes will be fetched from remote host.

flags

The value of flags can be any combination of the following flags, joined with the binary OR (|) operator.

Possible values for flags
Flag Description
MSG_OOB Process out-of-band data.
MSG_PEEK Receive data from the beginning of the receive queue without removing it from the queue.
MSG_WAITALL Block until at least len are received. However, if a signal is caught or the remote host disconnects, the function may return less data.
MSG_DONTWAIT With this flag set, the function returns even if it would normally have blocked.

Valorile întoarse

socket_recv() returns the number of bytes received, or FALSE if there was an error. 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.

Exemple

Example #1 socket_recv() example

This example is a simple rewrite of the first example from Exemple to use socket_recv().

<?php
error_reporting
(E_ALL);

echo 
"<h2>TCP/IP Connection</h2>\n";

/* Get the port for the WWW service. */
$service_port getservbyname('www''tcp');

/* Get the IP address for the target host. */
$address gethostbyname('www.example.com');

/* Create a TCP/IP socket. */
$socket socket_create(AF_INETSOCK_STREAMSOL_TCP);
if (
$socket === false) {
    echo 
"socket_create() failed: reason: " socket_strerror(socket_last_error()) . "\n";
} else {
    echo 
"OK.\n";
}

echo 
"Attempting to connect to '$address' on port '$service_port'...";
$result socket_connect($socket$address$service_port);
if (
$result === false) {
    echo 
"socket_connect() failed.\nReason: ($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 
"Sending HTTP HEAD request...";
socket_write($socket$instrlen($in));
echo 
"OK.\n";

echo 
"Reading response:\n\n";
$buf 'This is my buffer.';
if (
false !== ($bytes socket_recv($socket$buf2048MSG_WAITALL))) {
    echo 
"Read $bytes bytes from socket_recv(). Closing socket...";
} else {
    echo 
"socket_recv() failed; reason: " socket_strerror(socket_last_error($socket)) . "\n";
}
socket_close($socket);

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

The above example will produce something like:

<h2>TCP/IP Connection</h2>
OK.
Attempting to connect to '208.77.188.166' on port '80'...OK.
Sending HTTP HEAD request...OK.
Reading response:

Read 123 bytes from socket_recv(). Closing socket...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.

add a note add a note

User Contributed Notes 9 notes

up
9
dgk at tcde dot ru
9 years ago
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 = NULL, SLEEP_TIME_SECONDS, SLEEP_TIME_MILLISECONDS) !== FALSE) {
    if (in_array($my_socket, $streams)) {
        while (@socket_recv($my_socket, $data, 8192, 0)) {
            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 ;)
up
3
ss-130 at yandex dot ru
1 year ago
<?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:
// http://php.net/manual/en/function.socket-recv.php
//
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();
}

?>
up
1
rathamahata at rathamahata dot net
9 years ago
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/
up
2
davide dot renzi at gmail dot com
2 years ago
In PHP version 5.* there is a bug: MSG_DONTWAIT flag is not defined (see https://bugs.php.net/bug.php?id=48326)
up
1
m_lajos at hotmail dot com
2 months ago
Workaround for the missing MSG_DONTWAIT flag according to the bug report page:

<?php if(!defined('MSG_DONTWAIT')) define('MSG_DONTWAIT', 0x40); ?>
up
1
Anonymous
9 years ago
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.
up
1
bastiaan at [no-spam] megabass dot nl
10 years ago
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.
up
0
Anonymous
9 years ago
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.
up
0
engine at [NO SPAM] illusiononly dot com
9 years ago
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;
        }

     }
To Top