php进程类,PHP 守护进程类

搜索热词

下面是编程之家 jb51.cc 通过网络收集整理的代码片段。

编程之家小编现在分享给大家,也给大家做个参考。

用 PHP 实现的 Daemon 类。可以在服务器上实现队列或者脱离 crontab 的计划任务。

使用的时候,继承于这个类,并重写 _doTask 方法,通过 main 初始化执行。

class Daemon {

const DLOG_TO_CONSOLE = 1;

const DLOG_NOTICE = 2;

const DLOG_WARNING = 4;

const DLOG_ERROR = 8;

const DLOG_CRITICAL = 16;

const DAPC_PATH = '/tmp/daemon_apc_keys';

/**

* User ID

*

* @var int

*/

public $userID = 65534; // nobody

/**

* Group ID

*

* @var integer

*/

public $groupID = 65533; // nobody

/**

* Terminate daemon when set identity failure ?

*

* @var bool

* @since 1.0.3

*/

public $requireSetIdentity = false;

/**

* Path to PID file

*

* @var string

* @since 1.0.1

*/

public $pidFileLocation = '/tmp/daemon.pid';

/**

* processLocation

* 进程信息记录目录

*

* @var string

*/

public $processLocation = '';

/**

* processHeartLocation

* 进程心跳包文件

*

* @var string

*/

public $processHeartLocation = '';

/**

* Home path

*

* @var string

* @since 1.0

*/

public $homePath = '/';

/**

* Current process ID

*

* @var int

* @since 1.0

*/

protected $_pid = 0;

/**

* Is this process a children

*

* @var boolean

* @since 1.0

*/

protected $_isChildren = false;

/**

* Is daemon running

*

* @var boolean

* @since 1.0

*/

protected $_isRunning = false;

/**

* Constructor

*

* @return void

*/

public function __construct() {

error_reporting(0);

set_time_limit(0);

ob_implicit_flush();

register_shutdown_function(array(&$this,'releaseDaemon'));

}

/**

* 启动进程

*

* @return bool

*/

public function main() {

$this->_logMessage('Starting daemon');

if (!$this->_daemonize()) {

$this->_logMessage('Could not start daemon',self::DLOG_ERROR);

return false;

}

$this->_logMessage('Running...');

$this->_isRunning = true;

while ($this->_isRunning) {

$this->_doTask();

}

return true;

}

/**

* 停止进程

*

* @return void

*/

public function stop() {

$this->_logMessage('Stoping daemon');

$this->_isRunning = false;

}

/**

* Do task

*

* @return void

*/

protected function _doTask() {

// override this method

}

/**

* _logMessage

* 记录日志

*

* @param string 消息

* @param integer 级别

* @return void

*/

protected function _logMessage($msg,$level = self::DLOG_NOTICE) {

// override this method

}

/**

* Daemonize

*

* Several rules or characteristics that most daemons possess:

* 1) Check is daemon already running

* 2) Fork child process

* 3) Sets identity

* 4) Make current process a session laeder

* 5) Write process ID to file

* 6) Change home path

* 7) umask(0)

*

* @access private

* @since 1.0

* @return void

*/

private function _daemonize() {

ob_end_flush();

if ($this->_isDaemonRunning()) {

// Deamon is already running. Exiting

return false;

}

if (!$this->_fork()) {

// Coudn't fork. Exiting.

return false;

}

if (!$this->_setIdentity() && $this->requireSetIdentity) {

// required identity set Failed. Exiting

return false;

}

if (!posix_setsid()) {

$this->_logMessage('Could not make the current process a session leader',self::DLOG_ERROR);

return false;

}

if (!$fp = fopen($this->pidFileLocation,'w')) {

$this->_logMessage('Could not write to PID file',self::DLOG_ERROR);

return false;

} else {

fputs($fp,$this->_pid);

fclose($fp);

}

// 写入监控日志

$this->writeProcess();

chdir($this->homePath);

umask(0);

declare(ticks = 1);

pcntl_signal(SIGCHLD,array(&$this,'sigHandler'));

pcntl_signal(SIGTERM,'sigHandler'));

pcntl_signal(SIGUSR1,'sigHandler'));

pcntl_signal(SIGUSR2,'sigHandler'));

return true;

}

/**

* Cheks is daemon already running

*

* @return bool

*/

private function _isDaemonRunning() {

$oldPid = file_get_contents($this->pidFileLocation);

if ($oldPid !== false && posix_kill(trim($oldPid),0))

{

$this->_logMessage('Daemon already running with PID: '.$oldPid,(self::DLOG_TO_CONSOLE | self::DLOG_ERROR));

return true;

}

else

{

return false;

}

}

/**

* Forks process

*

* @return bool

*/

private function _fork() {

$this->_logMessage('Forking...');

$pid = pcntl_fork();

if ($pid == -1) {

// 出错

$this->_logMessage('Could not fork',self::DLOG_ERROR);

return false;

} elseif ($pid) {

// 父进程

$this->_logMessage('Killing parent');

exit();

} else {

// fork的子进程

$this->_isChildren = true;

$this->_pid = posix_getpid();

return true;

}

}

/**

* Sets identity of a daemon and returns result

*

* @return bool

*/

private function _setIdentity() {

if (!posix_setgid($this->groupID) || !posix_setuid($this->userID))

{

$this->_logMessage('Could not set identity',self::DLOG_WARNING);

return false;

}

else

{

return true;

}

}

/**

* Signals handler

*

* @access public

* @since 1.0

* @return void

*/

public function sigHandler($sigNo) {

switch ($sigNo)

{

case SIGTERM: // Shutdown

$this->_logMessage('Shutdown signal');

exit();

break;

case SIGCHLD: // Halt

$this->_logMessage('Halt signal');

while (pcntl_waitpid(-1,$status,WNOHANG) > 0);

break;

case SIGUSR1: // User-defined

$this->_logMessage('User-defined signal 1');

$this->_sigHandlerUser1();

break;

case SIGUSR2: // User-defined

$this->_logMessage('User-defined signal 2');

$this->_sigHandlerUser2();

break;

}

}

/**

* Signals handler: USR1

* 主要用于定时清理每个进程里被缓存的域名dns解析记录

*

* @return void

*/

protected function _sigHandlerUser1() {

apc_clear_cache('user');

}

/**

* Signals handler: USR2

* 用于写入心跳包文件

*

* @return void

*/

protected function _sigHandlerUser2() {

$this->_initProcessLocation();

file_put_contents($this->processHeartLocation,time());

return true;

}

/**

* Releases daemon pid file

* This method is called on exit (destructor like)

*

* @return void

*/

public function releaseDaemon() {

if ($this->_isChildren && is_file($this->pidFileLocation)) {

$this->_logMessage('Releasing daemon');

unlink($this->pidFileLocation);

}

}

/**

* writeProcess

* 将当前进程信息写入监控日志,另外的脚本会扫描监控日志的数据发送信号,如果没有响应则重启进程

*

* @return void

*/

public function writeProcess() {

// 初始化 proc

$this->_initProcessLocation();

$command = trim(implode(' ',$_SERVER['argv']));

// 指定进程的目录

$processDir = $this->processLocation . '/' . $this->_pid;

$processCmdFile = $processDir . '/cmd';

$processPwdFile = $processDir . '/pwd';

// 所有进程所在的目录

if (!is_dir($this->processLocation)) {

mkdir($this->processLocation,0777);

chmod($processDir,0777);

}

// 查询重复的进程记录

$pDirObject = dir($this->processLocation);

while ($pDirObject && (($pid = $pDirObject->read()) !== false)) {

if ($pid == '.' || $pid == '..' || intval($pid) != $pid) {

continue;

}

$pDir = $this->processLocation . '/' . $pid;

$pCmdFile = $pDir . '/cmd';

$pPwdFile = $pDir . '/pwd';

$pHeartFile = $pDir . '/heart';

// 根据cmd检查启动相同参数的进程

if (is_file($pCmdFile) && trim(file_get_contents($pCmdFile)) == $command) {

unlink($pCmdFile);

unlink($pPwdFile);

unlink($pHeartFile);

// 删目录有缓存

usleep(1000);

rmdir($pDir);

}

}

// 新进程目录

if (!is_dir($processDir)) {

mkdir($processDir,0777);

}

// 写入命令参数

file_put_contents($processCmdFile,$command);

file_put_contents($processPwdFile,$_SERVER['PWD']);

// 写文件有缓存

usleep(1000);

return true;

}

/**

* _initProcessLocation

* 初始化

*

* @return void

*/

protected function _initProcessLocation() {

$this->processLocation = ROOT_PATH . '/app/data/proc';

$this->processHeartLocation = $this->processLocation . '/' . $this->_pid . '/heart';

}

}

以上是编程之家(jb51.cc)为你收集整理的全部代码内容,希望文章能够帮你解决所遇到的程序开发问题。

如果觉得编程之家网站内容还不错,欢迎将编程之家网站推荐给程序员好友。

总结

以上是编程之家为你收集整理的PHP 守护进程类全部内容,希望文章能够帮你解决PHP 守护进程类所遇到的程序开发问题。

如果觉得编程之家网站内容还不错,欢迎将编程之家网站推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值