©
本文档使用
php.cn手册 发布
(PHP 4 >= 4.1.0, PHP 5)
socket_recv — Receives data from a connected socket
$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
.
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.
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. |
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.
Example #1 socket_recv() example
This example is a simple rewrite of the first example from 范例 to use socket_recv() .
<?php
error_reporting ( E_ALL );
echo "<h2>TCP/IP Connection</h2>\n" ;
$service_port = getservbyname ( 'www' , 'tcp' );
$address = gethostbyname ( 'www.example.com' );
$socket = socket_create ( AF_INET , SOCK_STREAM , SOL_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 , $in , strlen ( $in ));
echo "OK.\n" ;
echo "Reading response:\n\n" ;
$buf = 'This is my buffer.' ;
if ( false !== ( $bytes = socket_recv ( $socket , $buf , 2048 , MSG_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-8OK.
[#1] cottton at i-stats dot net [2014-10-13 02:17:51]
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
$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, $buf, 4096, 0)) >= 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) ? 0 : $received_bytes) . ' bytes',
0 // 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',
0 // 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',
0 // 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;
}
}
}
}
?>
[#2] m_lajos at hotmail dot com [2014-07-14 15:45:57]
Workaround for the missing MSG_DONTWAIT flag according to the bug report page:
<?php if(!defined('MSG_DONTWAIT')) define('MSG_DONTWAIT', 0x40); ?>
[#3] ss-130 at yandex dot ru [2013-07-17 11:09:43]
<?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();
}
?>
[#4] davide dot renzi at gmail dot com [2012-03-01 08:50:34]
In PHP version 5.* there is a bug: MSG_DONTWAIT flag is not defined (see https://bugs.php.net/bug.php?id=48326)
[#5] rathamahata at rathamahata dot net [2005-08-25 04:44:52]
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/
[#6] [2005-05-06 04:59:51]
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.
[#7] [2005-05-05 07:42:43]
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.
[#8] engine at [NO SPAM] illusiononly dot com [2004-11-30 04:58:28]
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;
}
}
[#9] dgk at tcde dot ru [2004-11-05 03:57:32]
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).
<?php
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 ;)
[#10] bastiaan at [no-spam] megabass dot nl [2004-04-05 09:35:32]
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.