我有以下方法:
public static function listen(int $port, callable $callback) {
ob_implicit_flush();
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
println("socket_create() failed: reason: " . socket_strerror(socket_last_error()));
}
if (socket_bind($sock, '127.0.0.1', $port) === false) {
println("socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock)));
}
if (socket_listen($sock, 5) === false) {
println("socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)));
}
if ($callback !== null && is_callable($callback)) {
call_user_func($callback);
}
do {
if (($msgsock = socket_accept($sock)) === false) {
println("socket_accept() failed: reason: " . socket_strerror(socket_last_error($sock)));
continue;
}
if (false === ($buf = socket_read($msgsock, 2048, PHP_BINARY_READ))) {
println("socket_read() failed: reason: " . socket_strerror(socket_last_error($msgsock)));
continue;
}
$eventName = trim(explode(' ', $buf)[1], '/');
$msg = '';
foreach (self::$events as $event) {
if ($event->name() == $eventName) {
$msg = $event->headers();
$msg .= $event->run();
break;
}
}
socket_write($msgsock, $msg, strlen($msg));
socket_close($msgsock);
println("socket closed");
} while (true);
socket_close($sock);
}
当我通过命令行运行它时,它工作正常。当我在浏览器中打开页面并从套接字请求内容时,它会输出正确的标题并在页面上显示正确的内容。
编辑代码时,按 Ctrl + C 并重新运行代码,我收到以下错误:
PHP Warning: socket_bind(): unable to bind address [98]: Address already in use in /path/to/file.php on line 20
socket_bind() failed: reason: Address already in use
这使得更新代码变得困难,因为我必须等待片刻,直到我再次运行代码。按下 Ctrl + C 时,我有办法关闭所有套接字吗?
我注意到只要我不在浏览器中加载它,我就可以开始和停止这个过程很多次。
答案 0 :(得分:1)
我不懂PHP,但一般来说,你需要为信号SIGINT注册一个处理程序,并关闭该处理程序中的所有开放资源。
请注意,如果您为SIGINT注册处理程序,Ctrl-C将不再终止该进程(它将改为触发处理程序),因此信号处理程序必须确保程序终止,如果这是您想要的
根据此answer到How do I catch a KILL or HUP or User Abort signal?,您应该在PHP中使用pcntl_signal来注册信号
编辑:显然,您必须启用ticks才能触发信号处理程序。一个小例子:
declare(ticks=1);
function sig_handler($signo)
{
switch ($signo) {
case SIGINT:
echo "Caught SIGINT, exiting.\n";
exit;
break;
default:
// handle all other signals
echo "Caught signal $signo...\n";
}
}
// setup signal handler
pcntl_signal(SIGINT, 'sig_handler');
for ($x = 0; $x <= 50; $x++) {
echo "main loop: $x\n";
sleep(1);
}
ticks
的值是响应度和开销之间的权衡。