【问题标题】:Can not bind to address because it is already in use无法绑定到地址,因为它已在使用中
【发布时间】:2016-06-20 22:17:37
【问题描述】:

我有以下方法:

    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 时,我有办法关闭所有套接字吗?

我注意到只要不在浏览器中加载它,我就可以多次启动和停止该过程。

【问题讨论】:

    标签: php sockets


    【解决方案1】:

    我不懂 PHP,但一般来说你需要为信号 SIGINT 注册一个处理程序,并关闭该处理程序中所有打开的资源。

    请注意,如果您为 SIGINT 注册了处理程序,Ctrl-C 将不再终止进程(而是触发处理程序),因此信号处理程序必须确保程序终止,如果这是您想要的.

    根据这个answerHow 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 的值是响应能力和开销之间的权衡。

    【讨论】:

    • 我认为我需要这样做,所以我尝试添加一个,但它没有执行回调。它会停止取消键盘输入。我把它放在do之前。
    • 关于放置,我建议尽早安装信号处理程序。
    • 我回家后试试看。
    • 我还必须使用socket_select(),因为socket_accept() 会阻塞。 socket_select() 不是。
    猜你喜欢
    • 1970-01-01
    • 2014-07-10
    • 1970-01-01
    • 1970-01-01
    • 2018-12-05
    • 1970-01-01
    • 2018-03-20
    • 1970-01-01
    • 2014-04-27
    相关资源
    最近更新 更多