我正在尝试启动一个php(在apache下)进程(通过从浏览器调用apache),它将在关闭apache服务器(sudo service apache2 stop)后仍然存在.即使我确保创建的进程没有父进程(parent 1),并且有它自己的会话,但是,不知何故,当我停止apache(或重新启动apache)时,进程还是死了.
我创建了一个test.php文件:
<?php
exec('setsid nohup sleep 1000 > /dev/null 2>/dev/null &');
?>
当我们对test.php执行HTTP GET时,确实会得到一个即时的OK响应,并且进程仍然存在。但是,当我们这样做时:
sudo service apache2 stop
睡眠进程死亡。当进程不属于它的组或会话,并且进程不是子进程时,如何杀死进程?
6条答案
按热度按时间piok6c0g1#
Apache可能会有一个派生进程的列表,并逐个杀死它们,而不是将它们作为一组。在这种情况下,列表中的所有进程都将被
kill(2)
ed。请查看
kill(2)
系统调用的手册页。在ERRORS部分,失败的唯一可能性是:EINVAL
,表示传递了无效的信号编号。此处不适用。ESRCH
,流程(或流程组)不存在。也不适用。EPERM
,您没有发送信号的权限。这在此处适用,但只有(这与进程层次结构或父关系无关)您可以向哪些进程发送信号,这些进程运行的真实/保存的用户id等于发送方进程的有效用户id。因此,由于Apache有一个它启动的所有进程的注册表,它能够终止进程是正常的。无论如何,您是否尝试过创建一个进程,从该进程创建一个子进程,并在孙子进程中执行
setsid
?这样,Apache进程就没有机会在派生进程列表中注册它。我没有尝试过,但它可以工作。从FreeBSD
kill(2)
手册页:对于有权向pid指定的进程发送信号的进程,用户必须是超级用户,或者**接收进程的真实的或已保存用户ID必须与发送进程的真实或有效用户ID匹配。**信号
SIGCONT
是一个例外,它始终可以发送到与发送方具有相同会话ID的任何进程。(重点是我)在linux中,几乎是一样的,除了
...(如果是发送进程)在目标进程的用户名称空间中具有
CAP_KILL
功能...但这里不适用。
yrefmtwq2#
我很好奇为什么apache服务器需要关闭,但是我倾向于说您可以尝试使用容器化的解决方案来完全不同的策略。公开一个可以触发您的php进程的nginx docker容器可能比使用Apache更稳定,因为docker守护进程总是以root身份运行。我认为这取决于您的用例的特定需求。因此解释一下为什么需要关闭Apache可能会得到更好的答案。
wztqucjr3#
列出所有活动进程(例如
ps aux
)。Apache创建的进程以用户www-data
的身份运行。当您停止Apache服务时,我怀疑它们会根据该列表或某个内部列表被终止。
apache2.service stop
调用apachectl -k graceful-stop。这将SIGTERM所有“子进程”。不幸的是,我无法在代码中找到确切的位置。也许有人可以这样做来验证假设。A解决方案:
以另一个用户的身份运行该流程。如何操作取决于您的情况。您必须定义某种接口。
例如,你可以让另一个进程监听
localhost
或者使用Unix域套接字,同样的事情也可以通过使用 gearman 来实现,正如@Akshay Vanjare在评论中指出的。然后,您的PHP指令码就可以呼叫界面。
无解决方案:
www-data
,您不能以另一个受密码保护的用户身份启动进程,因为su asks代表pass,switching UID不是一个好主意。su - NEW_USER -c "COMMAND"
。不要在任何你关心的系统中这样做。这是不安全的。* 非常 * 不安全。而且每次调用脚本时,你都会有一个新的进程。你必须小心地杀死它。进一步思考:
xurqigkl4#
首先关于我的答案,这不是一个好主意,控制守护程序从网络。
一旦这样说,你可以有一个PHP脚本,写一个标志或类似的东西,无论是在数据库,文件,redis等。
另一方面,创建一个PHP脚本,用cron来查找标记。如果找到了,脚本可以启动一个PHP守护进程来分离。注意运行cron脚本和PHP守护进程时要确保用户和权限。
但再次要小心安全问题。
fdx2calv5#
从PHP开发人员的Angular 来看,我不认为有一种方法可以实现这一点。
或者你可以实现一个队列和工作者来完成你的任务/执行。为此你可以使用Redis或任何其他数据库。
https://laravel.com/docs/9.x/queues
7vhp5slm6#
您可以编写一个服务,然后使用
sudo service start|stop|restart
进行控制您可以使用
visudo
来编辑sudoers档案,以允许www-data
使用sudo
来执行特定的sh
档案,而不需要密码提示。此sh档案将包含service your_service start
行。示例:我希望能够从客户端 AJAX 请求重新启动apache 2。
上下文:没有连接屏幕/键盘的文件服务器。我有SSH设置,但我不想在笔记本电脑中启动客户端。我用apache密码保护目录保护重新启动页面,沿着其他管理页面。例如:我有一个页面来重新启动/关闭整个系统。
"我这么做了“
注册要与
sudo service apache_restarter_service start
一起运行的服务此服务文件调用一个简单的
sh
脚本,它是一个两行脚本:sleep 1 second and then call service apache2 restart
.使用
visudo
编辑sudoers文件。允许用户www-data
使用sudo
运行调用service apache_restarter_service start
的sh脚本。服务文件只用于启动一个root权限的进程,不需要很长时间,所以在服务定义中不需要
Restart=always
,这个进程不能被apache杀死,apache甚至不会知道它,它只知道sh
脚本返回0。sudoers文件的更改示例:
from_php.sh
只调用service apache_restarter_service start
。这里不需要sudo
,因为你的php脚本在从_php. sh调用时已经使用了sudo。这里需要
from_php.sh
,因为你不希望php直接调用service
。因为你的脚本中的BUG或攻击可能会对你的服务器造成损害。这样,我们只在sudoers中授权了from_php.sh
。php脚本必须用
sudo
调用from_php.sh
,你可以使用exec("sudo /opt/apache_restarter/from_php.sh")
,但不需要在末尾加上&
,因为apache不会立即重启。服务定义文件
apache_restarter_service.service
的示例:为了避免服务在系统重新启动时运行。没有什么坏处,但也是无用的。你可以让服务总是禁用,并在启动它之前在
from.php
脚本中启用它。或者只是调整服务文件,使其在系统启动时不运行一次。您可以根据需要调整
StartLimitIntervalSec=0
。您可以将
User=root
调整为一个更安全、权限更低的用户。在我的情况下,我不在乎,但也许您会在乎。您可能希望使用www-data
。我不知道为什么这可能不起作用,但到目前为止,我还没有尝试使用www-data
。你可以用多种方式编写
run.sh
,并执行不同的任务,最简单的方法是等待1秒钟,然后用service apache2 restart
重新启动apache。虽然我感兴趣的是能够从客户端重新启动apache,但这也适用于生成一个在apache停止/重新启动时不会终止的进程。
我也尝试了
nohup
,&
,setsid
等等。我会保存人们一些时间。什么都不起作用。Apache应该像已经建议的那样终止所有子进程。