91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么用PHP寫守護進程類

發布時間:2021-09-03 22:26:03 來源:億速云 閱讀:296 作者:chen 欄目:開發技術

本篇內容主要講解“怎么用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寫守護進程類”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

php
AI

北碚区| 湖北省| 罗山县| 张家口市| 岐山县| 景泰县| 交口县| 鄂伦春自治旗| 罗定市| 聊城市| 肃宁县| 双峰县| 河北区| 邵阳县| 噶尔县| 手游| 淮北市| 西平县| 麻栗坡县| 朝阳县| 灌南县| 阳东县| 公安县| 灵宝市| 周宁县| 陵川县| 卢龙县| 犍为县| 濮阳市| 高邮市| 吐鲁番市| 竹北市| 萨迦县| 辰溪县| 鄂伦春自治旗| 益阳市| 黔南| 沁阳市| 彭阳县| 中方县| 云林县|