PHPデーモン

初心者のエクソシストへのメモ。

始める前に:phpDaemonとSystem_Daemonが何であるかを知っています。 私はこのテーマに関する記事を読んでいます。

それで、あなたはすでにあなたが悪魔を必要とすると決めたと仮定します。 彼は何ができるはずですか?

コンソールから取り外します


//    //    pcntl_fork()    :    $child_pid = pcntl_fork(); if ($child_pid) { //   ,   ,  exit(); } //    . posix_setsid(); //      ,      


pcntl_fork()関数は子プロセスを作成し、その識別子を返します。 ただし、変数$ child_pidは子プロセスに入りません(より正確には、0になります)。したがって、親プロセスのみがテストに合格します。 それは終了し、子プロセスはコードの実行を継続します。

通常、デーモンはすでに作成されていますが、コンソールにはすべての情報(エラーを含む)が表示されます。 はい。実行後すぐに終了します。

出力を再定義する


 $baseDir = dirname(__FILE__); ini_set('error_log',$baseDir.'/error.log'); fclose(STDIN); fclose(STDOUT); fclose(STDERR); $STDIN = fopen('/dev/null', 'r'); $STDOUT = fopen($baseDir.'/application.log', 'ab'); $STDERR = fopen($baseDir.'/daemon.log', 'ab'); 

ここで、標準出力ストリームを閉じて、それらをファイルに送信します。 念のため、STDINは/ dev / nullからの読み取り用に開かれています。 私たちの悪魔はコンソールから読み込まれません-それは解かれています。 これで、デーモンのすべての出力がファイルに記録されます。

行こう!


 include 'DaemonClass.php'; $daemon = new DaemonClass(); $daemon->run(); 

結論を再定義した後、デーモンに割り当てられたタスクを実行できます。 DaemonClass.phpを作成し、デーモンの基本的な作業を行うクラスの作成を開始します。

Daemonclass.php


 //    PHP     declare(ticks=1); class DaemonClass { //     public $maxProcesses = 5; //    TRUE,    protected $stop_server = FALSE; //       protected $currentJobs = array(); public function __construct() { echo "onstructed daemon controller".PHP_EOL; //   SIGTERM  SIGCHLD pcntl_signal(SIGTERM, array($this, "childSignalHandler")); pcntl_signal(SIGCHLD, array($this, "childSignalHandler")); } public function run() { echo "Running daemon controller".PHP_EOL; //  $stop_server    TRUE,    while (!$this->stop_server) { //       ,    while(count($this->currentJobs) >= $this->maxProcesses) { echo "Maximum children allowed, waiting...".PHP_EOL; sleep(1); } $this->launchJob(); } } } 

シグナルSIGTERM(シャットダウン)およびSIGCHLD(子プロセスから)が必要です。 デーモンが終了しないように、無限ループを開始します。 別の子プロセスを作成できるかどうかを確認し、できない場合は待機します。

  protected function launchJob() { //    //    pcntl_fork()   //  :    $pid = pcntl_fork(); if ($pid == -1) { //      error_log('Could not launch new job, exiting'); return FALSE; } elseif ($pid) { //      $this->currentJobs[$pid] = TRUE; } else { //       echo "  ID ".getmypid().PHP_EOL; exit(); } return TRUE; } 

エラーが発生した場合、 pcntl_fork()は-1を返します。$ pidは親プロセスで使用可能になり、この変数は子にはありません(より正確には、0になります)。

  public function childSignalHandler($signo, $pid = null, $status = null) { switch($signo) { case SIGTERM: //        $this->stop_server = true; break; case SIGCHLD: //       if (!$pid) { $pid = pcntl_waitpid(-1, $status, WNOHANG); } //      while ($pid > 0) { if ($pid && isset($this->currentJobs[$pid])) { //      unset($this->currentJobs[$pid]); } $pid = pcntl_waitpid(-1, $status, WNOHANG); } break; default: //    } } 

SIGTERM-正しいシャットダウンのシグナル。 SIGCHLD-子プロセスの完了のシグナル。 子プロセスの最後に、実行中のプロセスのリストから子プロセスを削除します。 SIGTERMを受信したら、フラグを設定します。現在のタスクが完了すると、「無限ループ」が終了します。

デーモンの複数のコピーの起動を禁止することは残っています。 これについては、 この記事で詳しく説明しています。

ご清聴ありがとうございました。

UPD: Dlussky habrayuzerのコメントでは、PHP> = 5.3.0では、 declare(ticks = 1)ではなくpcntl_signal_dispatch()を使用する必要があることが示唆されました。

Source: https://habr.com/ru/post/J134620/


All Articles