分享PHP守护进程类,分享php守护进程
用PHP实现的Daemon类。可以在服务器上实现队列或者脱离 crontab 的计划任务。
使用的时候,继承于这个类,并重写 _doTask 方法,通过 main 初始化执行。
<?php 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, array(&$this, 'sigHandler')); pcntl_signal(SIGUSR1, array(&$this, 'sigHandler')); pcntl_signal(SIGUSR2, array(&$this, '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); chmod($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'; } }
您可能感兴趣的文章:
- php守护进程 加linux命令nohup实现任务每秒执行一次
- PHP程序级守护进程的实现与优化的使用概述
- PHP实现多进程并行操作的详解(可做守护进程)
- shell脚本作为保证PHP脚本不挂掉的守护进程实例分享
- PHP高级编程实例:编写守护进程
- PHP守护进程实例
- PHP将进程作为守护进程的方法
- PHP扩展程序实现守护进程
- 如何写php守护进程(Daemon)

php把负数转为正整数的方法:1、使用abs()函数将负数转为正数,使用intval()函数对正数取整,转为正整数,语法“intval(abs($number))”;2、利用“~”位运算符将负数取反加一,语法“~$number + 1”。

实现方法:1、使用“sleep(延迟秒数)”语句,可延迟执行函数若干秒;2、使用“time_nanosleep(延迟秒数,延迟纳秒数)”语句,可延迟执行函数若干秒和纳秒;3、使用“time_sleep_until(time()+7)”语句。

php除以100保留两位小数的方法:1、利用“/”运算符进行除法运算,语法“数值 / 100”;2、使用“number_format(除法结果, 2)”或“sprintf("%.2f",除法结果)”语句进行四舍五入的处理值,并保留两位小数。

判断方法:1、使用“strtotime("年-月-日")”语句将给定的年月日转换为时间戳格式;2、用“date("z",时间戳)+1”语句计算指定时间戳是一年的第几天。date()返回的天数是从0开始计算的,因此真实天数需要在此基础上加1。

php判断有没有小数点的方法:1、使用“strpos(数字字符串,'.')”语法,如果返回小数点在字符串中第一次出现的位置,则有小数点;2、使用“strrpos(数字字符串,'.')”语句,如果返回小数点在字符串中最后一次出现的位置,则有。

方法:1、用“str_replace(" ","其他字符",$str)”语句,可将nbsp符替换为其他字符;2、用“preg_replace("/(\s|\ \;||\xc2\xa0)/","其他字符",$str)”语句。

php字符串有下标。在PHP中,下标不仅可以应用于数组和对象,还可应用于字符串,利用字符串的下标和中括号“[]”可以访问指定索引位置的字符,并对该字符进行读写,语法“字符串名[下标值]”;字符串的下标值(索引值)只能是整数类型,起始值为0。

查找方法:1、用strpos(),语法“strpos("字符串值","查找子串")+1”;2、用stripos(),语法“strpos("字符串值","查找子串")+1”。因为字符串是从0开始计数的,因此两个函数获取的位置需要进行加1处理。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

SublimeText3 Linux新版
SublimeText3 Linux最新版