问题遇到的现象和发生背景
在学习swoole的过程中,使用了目前最新的swoole 4.8.2,在使用swoole_event_add的时候,没有加入 Swoole\Event::wait(),导致监听无效,如果在swoole_event_add之后加上Swoole\Event::wait(),那么整个程序就阻塞在Swoole\Event::wait(),之后的代码就不再运行。
现在是使用swoole_event_add来监听文件变化,然后用pcntl_wait($status)阻塞读取子进程状态,还使用了pcntl_signal来绑定了接收到信号后的处理(重启子进程或者是关闭所有进程)。
最主要的问题事如何让swoole_event_add生效?
使用register_shutdown_function注册Swoole\Event::wait()也没用
问题相关代码,请勿粘贴截图
<?php
class Worker{
//监听socket
protected $socket = NULL;
//连接事件回调
public $onConnect = NULL;
public $reusePort=1;
//接收消息事件回调
public $onMessage = NULL;
public $workerNum=1; //子进程个数
public $allSocket; //存放所有socket
public $addr;
protected $worker_pid; //子进程pid
protected $master_pid;//主进程id
protected $watch_fd;//文件监视的句柄
public function __construct($socket_address) {
//监听地址+端口
$this->addr=$socket_address;
$this->master_pid=posix_getpid();
}
public function start() {
// register_shutdown_function(function () {
// Swoole\Event::wait();
// });
//获取配置文件
$test=include 'index.php';
$this->watch();//文件监视,发生改变之后发送信号
echo 'fork'.PHP_EOL;
$this->fork($this->workerNum);
echo 'start'.PHP_EOL;
$this->monitorWorkers(); //监视程序,捕获信号,监视worker进程
echo 'wait'.PHP_EOL;
Swoole\Event::wait();
}
/**
* 文件监视,自动重启
*/
$files=get_included_files();//引入的所有文件
foreach ($files as $file){
inotify_add_watch($init,$file,IN_MODIFY); //监视相关的文件,IN_MODIFU 修改状态
// stream_set_blocking($init,0);
//
// while (1){
// $events=inotify_read($init);//读取修改的信息
// if(!empty($events)){//发生了改动
// var_dump($events);
// if(!empty($events)){//发生了改动
// var_dump($events);
// }
// }
//监听
if(!empty($events)){//发生了改动
echo posix_getpid().'的'.(int)$fd.'文件发生了变化'.PHP_EOL;
posix_kill($this->master_pid,SIGUSR1);//发送信号
}
/**
*/
public function monitorWorkers(){
echo 'works'.PHP_EOL;
pcntl_signal(SIGUSR1, array($this, 'signalHandler'),false); //重启woker进程信号
//ctrl+c
pcntl_signal(SIGINT, array($this, 'signalHandler'),false); //杀死woker进程信号
echo 'wwwww';
$status=0;
while (1){
// 当发现信号队列,一旦发现有信号就会触发进程绑定事件回调
pcntl_signal_dispatch();//接受信号触发事件
echo '得到信号钱';
pcntl_wait($status)
//如果进程不是正常情况下的退出,重启子进程,我想要维持子进程个数
var_dump($pid,$status);
echo '得到信号后';
$index=array_search($pid,$this->worker_pid);
$index=array_search($pid,$this->worker_pid);
$this->fork(1);
var_dump('拉起子进程');
unset($this->worker_pid[$index]);
}
echo '执行1';
pcntl_signal_dispatch();//这里时担心在重启的过程中又接收到其他信号
}
}
public function signalHandler($sigo){
var_dump($sigo);
case SIGUSR1://接受到的信号
$this->reload();
echo "收到重启信号";
break;
case SIGINT:
$this->stopAll();
echo "按下ctrl+c,关闭所有字进程";
swoole_event_del($this->watch_fd);
exit(); break;
}
}
public function fork($worker_num){
for ($i=0;$i<$worker_num;$i++){
// $test=include 'index.php';//这里是父进程引入文件,应该会多次引入,没用测试
// var_dump($test);exit;
exit('创建失败');
}else if($pid>0){
//父进程空间,返回子进程id
while (true){
echo posix_getpid().PHP_EOL;
sleep(5);
}
}
echo '333'.PHP_EOL;;
// exit;//这里如果exit,主进程就会退出来,导致下面结束子进程的代码失效
// echo '1';
}
/**
* 重启worker进程
*/
public function reload(){
foreach ($this->worker_pid as $index=>$pid){
posix_kill($pid,SIGKILL); //结束进程
var_dump("杀掉的子进程",$pid);
unset($this->worker_pid[$index]);
$this->fork(1); //重新拉起worker
}
}
//捕获信号之后结束进程
public function stopAll(){
foreach ($this->worker_pid as $index=>$pid){
posix_kill($pid,SIGKILL); //结束进程
var_dump($pid.'关闭');
unset($this->worker_pid[$index]);
}
}
}
$worker = new Worker('tcp://0.0.0.0:9998');
$worker->start(); //启动
运行结果及报错内容
我的解答思路和尝试过的方法
我想要达到的结果
让进程监听文件修改状态的同时监听信号以及子进程的异常退出