我怎样才能在后台保持脚本 运行 不工作

How can I keep a script running in the background-not working

我正在尝试启动 Ratchet 的 chat-server.php 文件,该文件需要从 php 文件启动套接字服务器,这样每当客户端访问该页面时,服务器就会启动但它没有发生。这个 chat-server.php 文件需要从终端 运行 但我试图在用户访问时从主页 运行 它。

文件结构

./index.php

./config.php

./vendor/(all vendor files)

./src/MyApp/Chat.php

./js/app.js

./inc/connect.php <--Database connection file

./inc/send-message.php

./inc/startServer.php

./inc/bg.php

./inc/serverStatus.txt

./css/index.css

./css/reset.css

./bin/chat-server.php

config.php

<?php
    include_once ("./inc/startServer.php");
?>

聊天-server.php

<?php

    use Ratchet\Server\IoServer;
    use Ratchet\Http\HttpServer;
    use Ratchet\WebSocket\WsServer;
    use MyApp\Chat;


    if(isset($startNow)){ 

            require dirname(__DIR__) . '/vendor/autoload.php';

            $server = IoServer::factory(
                new HttpServer(
                    new WsServer(
                        new Chat()
                    )
                ),
                8080
            );

            $server->run();

    }

?>

bg.php

<?php
    $startNow = 1;
    include_once ("../bin/chat-server.php");
?>

startServer.php

<?php

$statusFile = dirname(__FILE__).'/serverStatus.txt';
$status = file_get_contents($statusFile);
if($status == "0"){

        function execInBackground($cmd) {
                if(substr(php_uname(), 0, 7) == "WINDOWS") {
                    pclose(popen('start /B ' . $cmd, 'r'));
                    file_put_contents($statusFile, 1);
                }
                else {
                    exec($cmd . ' > /dev/null &');
                    file_put_contents($statusFile, 1);
                }
        }

        execInBackground("php " . dirname(__FILE__) . "/bg.php");

}

?>

serverStatus.txt

其默认值已设置为0

注意: 相应地更新了代码,但现在仍然不起作用。

我不知道如何在发生任何故障时重新启动服务器或如何在所有客户端离开时关闭服务器。

我认为你应该阅读 http://php.net/manual/es/function.shell-exec.php

请注意,当PHP在安全模式下为运行时,此功能将被禁用。

当您使用相对路径包含文件时,您必须记住它们是相对于当前运行ning 文件,不只是当前文件.

在你的情况下。当您访问 index.php 并在其中包含 config.php 并且从那时起 startServer.php 一切正常,因为您包含 ./inc/startServer.php 相对于 index.php 是正确的。
但是你包含 ../inc/serverStatus.txt,这是不对的,因为你仍然 运行ning index.php 并且相对路径解析为 /../inc/serverStatus.txt 换句话说你正在尝试访问比您的 DOCUMENT_ROOT 高一级的文件。所以你永远不会进入你的 if 语句。
您可以使用 __FILE__ 常量,它始终解析为 当前文件 的绝对路径。所以你可以把你的 $statusFile 改成

$statusFile = dirname(__FILE__) . '/serverStatus.txt';

接下来是关于您的 exec()popen(pclose()) 命令。如果你想执行一些不在你的 PATH 环境变量中的命令,那么你 必须 指定文件的绝对路径。因为你不知道它会从哪个文件夹启动。它可能从 Apache 主目录启动,也可能从您用户的主目录启动。这取决于您 PHP 的设置是 sapi 模块还是 fcgi。无论如何,您需要将 execInBackground() 更改为

execInBackground("php " . dirname(__FILE__) . "/bg.php");

并在您的命令中添加一些空格,例如:

pclose(popen('start /B ' . $cmd, 'r'));
exec($cmd . ' > /dev/null &');

这样就不会出现一些奇怪的错误了。

在您的 bg.php 中,您需要更改当前工作目录,如下所示:

<?php
    $startNow = 1;
    chdir(dirname(__FILE__));
    include_once ("../bin/chat-server.php");
?>

这样,PHP 将找到 chat-server.php,无论您从哪个文件夹 运行 它。

顺便说一句,您打算如何停止服务器? =)


更新:您的函数 execInBackground() 中还有一个 变量作用域 问题。您的函数依赖于变量 $statusFile,但此变量在 全局范围 中定义,并且在函数内部不可见。要使其可见,您必须在访问 $statusFile 之前在函数中包含语句 global $statusFile;。像这样:

    function execInBackground($cmd) {
            global $statusFile;
            if (false !== stripos(PHP_OS, 'win')) {
                pclose(popen('start /B ' . $cmd, 'r'));
                file_put_contents($statusFile, 1);
            } else {
                exec($cmd . ' > /dev/null &');
                file_put_contents($statusFile, 1);
            }
    }

并且我已经更改了您检查 OS 的方式,因为您的方法包含错误。


更新2:

经过一堆测试,我发现当php-script 运行在后台(在Windows下)它不能使用"echo()"写入标准输出。当它发生时,php-script 会默默地死去,没有错误。因此,将所有 echo() 更改为某些对数函数。

将侦听端口更改为其他一些,当然是免费的,例如 50000。因为,8080 通常可能已被某些 Web 服务器或其他服务占用。

记住!只有拥有自己的服务器(如 VPS/VDS 或专用服务器)才能启动聊天服务器,在 public 主机 上没有人会允许您打开出于安全原因,一些用于传入连接的端口。在 public 服务器上,出于同样的原因,经常会禁用像 exec()popen() 和类似的功能。