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.

hek2mgl
  • 152,036
  • 28
  • 249
  • 266
donutdan4114
  • 1,262
  • 1
  • 8
  • 16

1 Answers1

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.

hek2mgl
  • 152,036
  • 28
  • 249
  • 266
  • 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? – donutdan4114 Nov 14 '14 at 16:23
  • Re-edited. I will create a new, more specific question, thanks! – donutdan4114 Nov 14 '14 at 16:29
  • @donutdan4114 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 ;) – hek2mgl Nov 14 '14 at 16:29
  • Thanks, I've added all the details to the Question, so others won't be confused. – donutdan4114 Nov 14 '14 at 16:30
  • Did you made it working with `socket_select()`? Should I provide an example? – hek2mgl Nov 14 '14 at 16:35
  • 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? – donutdan4114 Nov 14 '14 at 16:36
  • You need to give it a timeout and then run it in a loop – hek2mgl Nov 14 '14 at 16:38
  • 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.. – hek2mgl Nov 14 '14 at 16:39
  • I got it working! Calling `socket_set_nonblock($sock);` after `socket_listen()` works as intended. – donutdan4114 Nov 14 '14 at 16:41
  • 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? – donutdan4114 Nov 14 '14 at 16:42
  • @donutdan4114 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()` – hek2mgl Nov 14 '14 at 16:42
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/64956/discussion-between-donutdan4114-and-hek2mgl). – donutdan4114 Nov 14 '14 at 16:43