<?php
class DaemonCommand
{
private $info_dir = "/tmp";
private $pid_file = "";
private $terminate = false;
private $workers_count = 0;
private $gc_enabled = null;
private $workers_max = 8;
public function __construct($is_sington = false, $user = 'nobody', $output = "/dev/null")
{
$this->is_sington = $is_sington;
$this->user = $user;
$this->output = $output;
$this->checkPcntl();
}
public function checkPcntl()
{
if (!function_exists('pcntl_signal_dispatch')) {
declare(ticks=10);
}
if (!function_exists('pcntl_signal')) {
$message = 'PHP does not appear to be compiled with the PCNTL extension. This is neccesary for daemonization';
$this->_log($message);
throw new Exception($message);
}
pcntl_signal(SIGTERM, array(__CLASS__, "signalHandler"), false);
pcntl_signal(SIGINT, array(__CLASS__, "signalHandler"), false);
pcntl_signal(SIGQUIT, array(__CLASS__, "signalHandler"), false);
if (function_exists('gc_enable')) {
gc_enable();
$this->gc_enabled = gc_enabled();
}
}
public function daemonize()
{
global $stdin, $stdout, $stderr;
global $argv;
set_time_limit(0);
if (php_sapi_name() != "cli") {
die("only run in command line mode\n");
}
if ($this->is_sington == true) {
$this->pid_file = $this->info_dir . "/" . __CLASS__ . "_" . substr(basename($argv[0]), 0, -4) . ".pid";
$this->checkPidfile();
}
umask(0);
if (pcntl_fork() != 0) {
exit();
}
posix_setsid();
if (pcntl_fork() != 0) {
exit();
}
chdir("/");
$this->setUser($this->user) or die("cannot change owner");
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
$stdin = fopen($this->output, 'r');
$stdout = fopen($this->output, 'a');
$stderr = fopen($this->output, 'a');
if ($this->is_sington == true) {
$this->createPidfile();
}
}
public function checkPidfile()
{
if (!file_exists($this->pid_file)) {
return true;
}
$pid = file_get_contents($this->pid_file);
$pid = intval($pid);
if ($pid > 0 && posix_kill($pid, 0)) {
$this->_log("the daemon process is already started");
} else {
$this->_log("the daemon proces end abnormally, please check pidfile " . $this->pid_file);
}
exit(1);
}
public function createPidfile()
{
if (!is_dir($this->info_dir)) {
mkdir($this->info_dir);
}
$fp = fopen($this->pid_file, 'w') or die("cannot create pid file");
fwrite($fp, posix_getpid());
fclose($fp);
$this->_log("create pid file " . $this->pid_file);
}
public function setUser($name)
{
$result = false;
if (empty($name)) {
return true;
}
$user = posix_getpwnam($name);
if ($user) {
$uid = $user['uid'];
$gid = $user['gid'];
$result = posix_setuid($uid);
posix_setgid($gid);
}
return $result;
}
public function signalHandler($signo)
{
switch ($signo) {
case SIGUSR1:
if ($this->workers_count < $this->workers_max) {
$pid = pcntl_fork();
if ($pid > 0) {
$this->workers_count++;
}
}
break;
case SIGCHLD:
while (($pid = pcntl_waitpid(-1, $status, WNOHANG)) > 0) {
$this->workers_count--;
}
break;
case SIGTERM:
case SIGHUP:
case SIGQUIT:
$this->terminate = true;
break;
default:
return false;
}
}
*开始开启进程
*$count 准备开启的进程数
*/
public function start($count = 1)
{
$this->_log("daemon process is running now");
pcntl_signal(SIGCHLD, array(__CLASS__, "signalHandler"), false);
while (true) {
if (function_exists('pcntl_signal_dispatch')) {
pcntl_signal_dispatch();
}
if ($this->terminate) {
break;
}
$pid = -1;
if ($this->workers_count < $count) {
$pid = pcntl_fork();
}
if ($pid > 0) {
$this->workers_count++;
} elseif ($pid == 0) {
pcntl_signal(SIGTERM, SIG_DFL);
pcntl_signal(SIGCHLD, SIG_DFL);
if (!empty($this->jobs)) {
while ($this->jobs['runtime']) {
if (empty($this->jobs['argv'])) {
call_user_func($this->jobs['function'], $this->jobs['argv']);
} else {
call_user_func($this->jobs['function']);
}
$this->jobs['runtime']--;
sleep(2);
}
exit();
}
return;
} else {
sleep(2);
}
}
$this->mainQuit();
exit(0);
}
public function mainQuit()
{
if (file_exists($this->pid_file)) {
unlink($this->pid_file);
$this->_log("delete pid file " . $this->pid_file);
}
$this->_log("daemon process exit now");
posix_kill(0, SIGKILL);
exit(0);
}
public function setJobs($jobs = array())
{
if (!isset($jobs['argv']) || empty($jobs['argv'])) {
$jobs['argv'] = "";
}
if (!isset($jobs['runtime']) || empty($jobs['runtime'])) {
$jobs['runtime'] = 1;
}
if (!isset($jobs['function']) || empty($jobs['function'])) {
$this->log("你必须添加运行的函数!");
}
$this->jobs = $jobs;
}
private function _log($message)
{
printf("%s\t%d\t%d\t%s\n", date("c"), posix_getpid(), posix_getppid(), $message);
}
}
$daemon = new DaemonCommand(true);
$daemon->daemonize();
$daemon->start(2);
work();
$daemon = new DaemonCommand(true);
$daemon->daemonize();
$daemon->addJobs(array('function' => 'work', 'argv' => '', 'runtime' => 1000));
$daemon->start(2);
function work()
{
echo "测试1";
}
?>
评论