pcntl_signal function not being hit and CTRL+C doesn't work when using sockets
Asked Answered
S

1

3

I have a simple PHP script that I want to run from the terminal, and be able to process signal codes. The script creates a TCP server and processes connections. Not sure why, but I can't get signal processing to work:

<?php
declare(ticks = 1);

// Register shutdown command.
pcntl_signal(SIGINT, function ($sig) {
  echo 'Exiting with signal: ' . $sig;
  global $sock;
  global $client;
  socket_close($sock);
  socket_close($client);
  exit(1);
});

$address = '127.0.0.1';
$port = 1234;

$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($sock, $address, $port) or die('Could not bind to address.');
socket_listen($sock);

while (TRUE) {
  $client = socket_accept($sock);
  if ($client) {
    $input = socket_read($client, 1024000);
    socket_write($client, var_export($input, TRUE));
    socket_write($client, 'End of data transmission.');
    socket_close($client);
  }
  usleep(100);
}

CTRL+C does not kill the application or hit the function.
If I remove the pcntl_signal functions, CTRL+C kills the program as expected.

Based on the research I've done, this setup should work. I've tried it in PHP 5.5 and 5.6... Cannot get to work as intended.

Submersible answered 14/11, 2014 at 16:11 Comment(0)
M
5

Problem

The problem is that you are using socket_read() which performs blocking IO. PHP isn't able to process signals if it hangs in a blocking IO operation.

Solution

Use non blocking IO to read data from the socket. You can use the function socket_select() with a timeout in a loop to make sure a read wouldn't block.

Motive answered 14/11, 2014 at 16:16 Comment(12)
That worked! I've updated my question though to the real world example I am trying to setup. For some reason it's not working there. I'm assuming it might be an issue with sockets in general?... Is there a better way to set that up?Submersible
Re-edited. I will create a new, more specific question, thanks!Submersible
@Submersible Ok, I think this would be the best. And it would get upvoted, since the problem you are describing is very interesting. Also an answer is already prepared for you ;)Motive
Thanks, I've added all the details to the Question, so others won't be confused.Submersible
Did you made it working with socket_select()? Should I provide an example?Motive
It appears that the application is hanging on socket_accept()? $client isn't set, and the other code isn't hit until a connection is made. Does that sound right?Submersible
You need to give it a timeout and then run it in a loopMotive
btw, your problem is definitely a +1 (even if you needed two tries ;) ... I remember that I spent huge time on finding this out for the first time. It isn't well documented..Motive
I got it working! Calling socket_set_nonblock($sock); after socket_listen() works as intended.Submersible
Okay that didn't work so good when using ab -n 10000 -c 10 http://127.0.0.1:1234/... Can you go into more detail on the timeout solution?Submersible
@Submersible It may seem working for you, but the problem is, that you now aren't able to read all data from the client. In all situations where not all the output from client is immediately available your script would read nothing when you use socket_set_nonblock()Motive
Let us continue this discussion in chat.Submersible

© 2022 - 2024 — McMap. All rights reserved.