【问题标题】:How can I keep a script running in the background-not working如何让脚本在后台运行 - 不起作用
【发布时间】:2016-11-12 10:40:28
【问题描述】:

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

文件结构

./index.php

./config.php

./vendor/(所有供应商文件)

./src/MyApp/Chat.php

./js/app.js

./inc/connect.php

./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");
?>

聊天服务器.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

注意:相应地更新了代码,但现在仍然无法使用。

另外我不知道如何在出现任何故障时重新启动服务器,也不知道如何在所有客户端离开时关闭服务器。

【问题讨论】:

  • 我真的不明白为什么这个问题被否决但仍然感谢它。
  • 您正在为每个客户端启动一个新服务器?为什么需要手动启动服务器而不是让它在后台运行?这个问题只是尖叫XY问题。
  • @PeeHaa,不,这段代码应该只为所有客户端启动一个服务器。看一下,有关于服务器状态的检查。
  • 为什么要手动启动服务器?再次:XY Problem
  • @PeeHaa 首先,我使用 Ratchet 来构建聊天应用程序。在 Ratchet 文档中,我们被要求从终端启动一个名为 chat-server.php 的文件,该文件将打开 Web 套接字。所以我们需要手动启动它们(在WIN中)。在 *nix 中我们可以使用 supervisord。因此,想象在公共服务器上使用聊天应用程序时,管理员需要在每次用户想要使用它时进入终端。

标签: php filepath popen ratchet pclose


【解决方案1】:

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

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

【讨论】:

【解决方案2】:

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

在你的情况下。当您访问 index.php 并在其中包含 config.php 并从那时起 startServer.php 一切正常,因为您包含 ./inc/startServer.php 这是正确的,相对于 index.php
但是比您包含../inc/serverStatus.txt,这是不对的,因为您仍在运行index.php,并且该相对路径解析为/../inc/serverStatus.txt,换句话说,您正在尝试访问比@987654329 高一级的文件@。所以你永远不会进入你的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);
            }
    }

我已经改变了您检查操作系统的方式,因为您的方法包含错误。


UPDATE2

经过一堆测试,我发现当 php-script 在后台(在 Windows 下)运行时,它不能使用“echo()”来写入 STDOUT。当它发生时,php-script 会默默地死掉,没有错误。因此,将所有 echo() 更改为一些日志功能。

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

记住!只有当您拥有自己的服务器(如 VPS/VDS 或专用服务器)时,您才能启动聊天服务器,在 公共主机 上,出于安全原因,没有人会允许您为传入连接打开某些端口。在公共服务器上,由于相同的原因,经常会禁用 exec()popen() 等功能。

【讨论】:

  • 我真的不知道如何停止服务器。也许当所有用户离开时它应该停止,而且我需要一种方法来重新启动服务器,以防它以某种方式失败。
  • 我改变了你所说的方式,但它仍然让我“断开连接”。
  • 所做的更改导致了一些尴尬的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-09
  • 2016-06-03
  • 2021-04-06
  • 2023-03-23
  • 2021-12-23
  • 1970-01-01
  • 2022-12-22
相关资源
最近更新 更多