Home » Php » php – Can't read from socket (hangs)

php – Can't read from socket (hangs)

Posted by: admin July 12, 2020 Leave a comment

Questions:

Edit: Sorry, accidentally posted with a title for a different question. Fixed.

Hey guys,

I’m using PHP to connect to a local C++ socket server to keep state between a web app and a couple of daemons. I can send data to the socket server, but not receive from it; it just blocks on socket_read() and hangs indefinitely. Am I forgetting something dumb (like a NULL character or a different combination of newline characters)? The PHP is below:

socket_connect($sock, $addr, $port); 
socket_write($sock, 'Hello world');
$str = '';
while($resp = socket_read($sock, 1000))
    $str .= $resp;
socket_close($sock);
die("Server said: {$str}");

The related part of the socket server is below (note that the << and >> operators are overloaded):

std::string data;
sock >> data;
sock << data << std::endl;

Where >> calls Socket::recv(std::string&) and >> calls Socket::send(const std::string&).

This works fine from (for example) telnet, but PHP doesn’t want to play nice. Any thoughts/suggestions are appreciated.

How to&Answers:

Sockets in PHP, as in most programming languages, are opened in blocking mode by default, unless set otherwise using socket_set_nonblock.

This means that unless a timeout/error occurs or data is received, socket_read will hang there forever.

Since your termination character seems to be a new line, try that:

while($resp = socket_read($sock, 1000)) {
   $str .= $resp;
   if (strpos($str, "\n") !== false) break;
}
socket_close($sock);
die("Server said: $str");

Answer:

TCP sockets usually try to combine multiple small send calls into one packet to avoid sending too many packets (Nagle’s algorithm). This may be the cause that you can’t receive anything after the send() call. You will have to open the socket with TCP_NODELAY to avoid that.

Answer:

I actually just fixed a problem similar to this, except with pipes (Is php's fopen incompatible with the POSIX open for pipes). I don’t know to what extent the solution would be similar, but maybe worth a look? I agree with RageD that you should stick a cout between the read and write lines just to test and see if the C++ is hanging on the sock >> data line or the sock << data line…

Answer:

You can also try this when reading from socket:

if(socket_recv ( $socket , $response , 2048 , MSG_PEEK)!==false)
{
   echo "Server said: $response";
}

Note: Using MSG_WAITALL in place of MSG_PEEK might cause socket to hang (from one experience I once had).