如何让脚本在后台运行 - 不工作
我试图启动棘轮的chat-server.php文件,该文件需要从php文件启动套接字服务器,以便每当客户端访问页面服务器启动,但没有发生。这chat-server.php文件需要从终端运行,但我试图在用户访问时从主页面运行它。如何让脚本在后台运行 - 不工作
文件结构
./index.php
./config.php
./vendor/(all供应商文件)
./src/MyApp /Chat.php
./js/app.js
./inc/connect.php < --database连接文件
./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
它的默认值已被设置为
注意:相应地更新了代码,但现在仍然不起作用。
加我对重新启动服务器以避免任何故障或在所有客户端离开时如何关闭服务器没有任何意见。
当包括使用相对路径你必须记住,他们是相对于当前运行文件,不仅仅是当前文件文件。
在你的情况。当您访问index.php
并包括其中config.php
,然后从startServer.php
这一切都可以,因为您包括./inc/startServer.php
这是正确的,相对于index.php
。
但是,如果包含../inc/serverStatus.txt
,这是不正确的,因为您仍在运行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
无论从哪个文件夹中,您将运行它的事情。
顺便说一句,你是怎么计划停止你的服务器? =)
UPDATE:你也有你的功能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脚本在后台运行(在Windows下),当它不能使用“回声()”来写STDOUT。当它发生时,php-script将会静静地死去,没有任何错误。因此,将所有echo()
都改为某些日志功能。
将监听端口更改为某些其他可以肯定免费使用的端口,例如50000.因为8080通常可能已被某些Web服务器或其他服务占用。
还记得!只有当您拥有自己的服务器(如VPS/VDS或专用服务器)时,您才可以启动聊天服务器,公共托管由于安全原因,没有人会允许您打开某些端口以接收传入连接。在公共服务器上,出于相同的原因,通常会有禁用的功能,如exec()
,popen()
等。
我想你应该阅读http://php.net/manual/es/function.shell-exec.php
注意,当PHP在安全模式下运行此功能被禁用。
我的本地主机没有在安全模式下运行,我从http://php.net/manual/en/function.popen.php复制了代码。这是关于运行一些后台进程。 – Ayan
我真的不知道为什么这个问题是downvote,但仍然感谢它。 – Ayan
您正在为每个客户启动一个新服务器?为什么你需要手动启动服务器而不是在后台运行?这个问题只是尖叫XY问题。 – PeeHaa
@PeeHaa,不,这个代码应该只为所有的客户端启动一个服务器。看看,有关于服务器状态的检查。 – spirit