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/
socket_recv
(PHP 4 >= 4.1.0, PHP 5)
socket_recv — Reçoit des données d'un socket connecté
Description
$socket
, string &$buf
, int $len
, int $flags
)
La fonction socket_recv() reçoit
len octets de données dans buf depuis
socket. socket_recv() peut être utilisée
pour récupérer des données depuis des sockets connectés. Aussi, des drapeaux
permettent de changer le comportement de la fonction.
buf est passé par référence, il doit donc être présent
dans la liste des arguments. Les données reçues depuis la
socket par socket_recv()
seront retournées dans buf.
Liste de paramètres
-
socket -
socketdoit être une ressource de socket précédemment créée par socket_create(). -
buf -
Les données reçues seront transmises dans
buf. Si une erreur survient, si la connexion est fermée ou si aucune donnée n'est disponible,bufvaudra alorsNULL. -
len -
Jusqu'à
lenoctets seront lus depuis l'hôte distant. -
flags -
La valeur de
flagspeut être une combinaison des drapeaux suivants, groupés au moyen de l'opérateur binaire OR (|).Valeurs possibles de flagsFlag Description MSG_OOBTraite des données hors de bande. MSG_PEEKReçoit les données depuis le début de la queue sans pour autant les supprimer de la queue. MSG_WAITALLBloque avant qu'au moins lensont reçues. Cependant, si un signal est intercépté ou si la connexion est terminée, la fonction pourra retourner moins de données.MSG_DONTWAITSi ce drapeau est spécifié, la fonction retournera ses données alors qu'en temps normal elle aurait bloqué.
Valeurs de retour
socket_recv() retourne le nombre d'octets reçus,
ou FALSE si une erreur est apparue. Le code d'erreur actuel peut être
récupéré en appelant socket_last_error(). Ce code
d'erreur peut être passé à la fonction socket_strerror()
pour avoir une représentation textuelle de l'erreur.
Exemples
Exemple #1 Exemples avec socket_recv()
Cet exemple est une réécriture de l'exemple pris sur Exemples pour utiliser socket_recv().
<?php
error_reporting(E_ALL);
echo "<h2>TCP/IP Connection</h2>\n";
/* Récupère le port du service WWW. */
$service_port = getservbyname('www', 'tcp');
/* Récupère l'adresse IP de l'hôte cible. */
$address = gethostbyname('www.example.com');
/* Crée un socket TCP/IP. */
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
echo "socket_create() a échoué: raison: " . socket_strerror(socket_last_error()) . "\n";
} else {
echo "OK.\n";
}
echo "Tentative de connexion à '$address' sur le port '$service_port'...";
$result = socket_connect($socket, $address, $service_port);
if ($result === false) {
echo "socket_connect() a échoué.\nRaison: ($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 .= "Connexion: Fermée\r\n\r\n";
$out = '';
echo "Envoi d'une requête HTTP HEAD...";
socket_write($socket, $in, strlen($in));
echo "OK.\n";
echo "Lecture de la réponse:\n\n";
$buf = 'Ceci est mon buffer.';
if (false !== ($bytes = socket_recv($socket, $buf, 2048, MSG_WAITALL))) {
echo "$bytes octets lus depuis socket_recv(). Fermeture du socket...";
} else {
echo "socket_recv() a échoué; raison: " . socket_strerror(socket_last_error($socket)) . "\n";
}
socket_close($socket);
echo $buf . "\n";
echo "OK.\n\n";
?>
L'exemple ci-dessus produit un résultat ressemblant à celà:
<h2>TCP/IP Connection</h2> OK. Tentative de connexion à '208.77.188.166' sur le port '80'...OK. Envoi d'une requête HTTP HEAD...OK. Lecture de la réponse: 123 octets lus depuis socket_recv(). Fermeture du 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 Connexion : Fermée Content-Type: text/html; charset=UTF-8 OK.
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;
}
}
In PHP version 5.* there is a bug: MSG_DONTWAIT flag is not defined (see https://bugs.php.net/bug.php?id=48326)
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.
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.
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 ;)
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.
