php守护进程

PHP实现守护进程

<?php
declare(ticks = 1);// 必须声明,不然pcntl_signal不起作用,否则在while中调用pcntl_signal_dispatch

abstract class Daemon 
{
    protected $pidFile = null;
    protected $running = true;

    public function __construct()
    {
        if (php_sapi_name() != 'cli') {
            $this->log('not cli environment', true);
        }

        global $argc, $argv;

        $this->argc = $argc;
        $this->argv = $argv;
    }

    public function dispatcher()
    {
        switch ($this->argv[1]) {
            case 'start':
                $this->start();
                break;
            case 'stop':
                $this->stop();
                break;
            case 'restart':
                $this->restart();
                break;
            case 'wait':
                $this->wait();
                break;
            default:
                $this->def();
        }
    }
    
    public function wait()
    {
        // 发送一个暂停信号
        posix_kill($this->getPid(), SIGINT);
    }

    public function restart()
    {
        // 发送一个重启信号
        posix_kill($this->getPid(), SIGUSR1);
    }   


    public function def()
    {
        echo "i don't know what to do";
        exit(0);
    }

    public function start()
    {
        // 使php变成守护进程(放到后台执行)
        $pid = pcntl_fork();
        if ($pid < 0) {
            $this->log('pcntl_fork fail', true);
        } elseif ($pid) {
            exit(0); // 退出父进程
        }

        if (posix_setsid() < 0) {
            $this->log('setsid fail', true);
        }
        $curPid = posix_getpid();
        if (!$this->savePid($curPid)) {
            $this->log('save pid fail', true);
        }

        // 注册信号处理函数
        $this->registerSignHandler();
        $this->run();
    }

    public function registerSignHandler()
    {   
        pcntl_signal(SIGINT, array($this, 'sigHandler'));
        pcntl_signal(SIGUSR1,array($this, 'sigHandler'));
        pcntl_signal(SIGTERM,array($this, 'sigHandler'));
    }

    public function sigHandler($signo)
    {
        switch ($signo) {
            case SIGTERM:
                $this->stop();
                break;
            case SIGUSR1:
                $this->running = true;
                break;
            case SIGINT:
                $this->running = false;
                break;
            default:
                echo "handle all other signals...\n";
        }
    }

    public function getPidFile()
    {
        return $this->argv[0] . '.pid';
    }

    public function getPid()
    {
        if (is_file($this->getPidFile())) {
            return file_get_contents($this->getPidFile());
        }
        $this->log('pid file no found', true);
    }

    public function savePid($curPid, $path = null)
    {
        if (is_null($path)) {
            $path = $this->getPidFile();
        }
        return file_put_contents($path, $curPid, LOCK_EX);
    }

    public function stop()
    {
        $pidFile = $this->getPidFile();
        if (file_exists($pidFile)) {
            $pid = $this->getPid();
            posix_kill($pid, SIGTERM);            
            unlink($this->getPidFile());
        }
    }

    public function log($msg, $shutdown)
    {
        $this->logQueue[] = $msg;
        if ($shutdown == true) {
            $this->logRender();
            exit(-1);
        }
    }

    public function logRender()
    {
        print_r($this->logQueue);
    }

    abstract public function run();
}

class EmailDaemon extends Daemon
{
    public function run()
    {
        while (true) {
            while ($this->running) {
                echo 'sending email...';
                echo PHP_EOL;
                sleep(1);
            }  
        }
    }
}

$daemon = new EmailDaemon();
$daemon->dispatcher();

php实现守护进程的两种方式

https://blog.csdn.net/zhang197093/article/details/52226349

进程以某个用户运行, 比如www

class Process {

    public static function runAs($name) {
        $userInfo = posix_getpwnam($name);
        if ($userInfo) {
            $gid = $userInfo['gid'];
            $uid = $userInfo['uid'];
            return posix_setegid($gid) && posix_seteuid($uid);
        }
        return false;
    }

}

daemonize方式

function daemonize()
{
    $pid = pcntl_fork();
    if ($pid == -1) {
        die("fork(1) failed!\n");
    } elseif ($pid > 0) {
        //让由用户启动的进程退出
        exit(0);
    }
    //建立一个有别于终端的新session以脱离终端
    posix_setsid();
    $pid = pcntl_fork();
    if ($pid == -1) {
        die("fork(2) failed!\n");
    } elseif ($pid > 0) {
        //父进程退出, 剩下子进程成为最终的独立进程
        exit(0);
    }
}
daemonize();
sleep(1000);

标签: none