How to write PHP daemon (Daemon) _php tips

Source: Internet
Author: User
Tags garbage collection sessions sleep stdin

A daemon (Daemon) is a special process running in the background. It is independent of the control terminal and periodically performs a task or waits to handle certain occurrences. The daemon is a very useful process. PHP can also implement the Daemon function.
I. Basic Concepts
Process:Each process has a parent process, and the child process exits, and the parent process gets the status of the child process exiting.
Process Group:Each process belongs to a process group, and each process group has a process group number that equals the PID of the process group leader
second, the Guardian programming essentials
1. Run in the background
To avoid suspending the control terminal to put daemon into the background execution. The method is to call fork in the process to terminate the parent process, allowing the daemon to execute in the background in the child process. if ($pid =pcntl_fork ()) exit (0);//is the parent process that ends the parent process and the child process continues
2. Out of control terminals, login sessions and process groups
It is necessary to introduce the process and control terminal in Linux, the relationship between the logon session and the process group: the process belongs to a process group, and the process group number (GID) is the process number (PID) of the process leader. A logon session can contain multiple process groups. These process groups share a control terminal. This control terminal is usually the login terminal that creates the process. Control terminals, logon sessions and process groups are usually inherited from the parent process. Our aim is to get rid of them from their influence. The method is based on the 1th, invoking Setsid () to make the process the session leader: Posix_setsid ();
Description: The SETSID () call fails when the process is the session leader. But the 1th has ensured that the process is not the conversation leader. After the Setsid () call succeeds, the process becomes the new session leader and the new process leader, and is detached from the original logon session and process group. Because the session process is exclusive to the control terminal, the process is also detached from the control terminal.
3. Disable process Reopen control terminal
Now, the process has become a session leader without terminals. But it can reapply to open a control terminal. You can prevent a process from reopening the control terminal by making the process no longer the session leader: if ($pid =pcntl_fork ()) exit (0);//End the first child process, the second child process continues (the second subprocess is no longer the session leader)
4. Close the Open file descriptor
The process inherits the open file descriptor from the parent process that created it. Without shutting down, system resources will be wasted, causing the file system in which the process is located to fail to unload and cause unexpected errors. Close them as follows:
Fclose (STDIN), fclose (STDOUT), fclose (STDERR) turn off standard input output and error display.
5. Change the current working directory
The file system in which the working directory resides cannot be unloaded when the process is active. It is generally necessary to change the working directory to the root directory. The process for the write run log changes the working directory to a specific directory such as ChDir ("/") for the need to dump the core.
6. Reset File Creation Mask
The process inherits the file creation mask from the parent process that created it. It may modify the access bit of the file created by the daemon. To prevent this, create a mask purge of the file: Umask (0);
7. Processing SIGCHLD Signal
Processing of SIGCHLD signals is not necessary. However, for some processes, especially server processes, it is often necessary to generate a subprocess processing request when the request arrives. If the parent process does not wait for the child process to end, the child process becomes a zombie process (zombie) that consumes system resources. If the parent process waits for the child process to end, it will increase the burden on the parent process and affect the concurrency performance of the server process. The operation of the SIGCHLD signal can be simply set to Sig_ign under Linux. Signal (sigchld,sig_ign);
In this way, the kernel does not produce a zombie process at the end of the subprocess. Unlike BSD4, BSD4 must explicitly wait for the child process to end before releasing the zombie process. Please refer to the Linux signal Description list for the signal issue
Iii. Examples

<?php * Background Script Control class */class daemoncommand{private $info _dir= "/tmp"; 
  Private $pid _file= ""; Private $terminate =false; 
  Whether to interrupt private $workers _count=0; 
  Private $GC _enabled=null; Private $workers _max=8; run up to 8 processes public function __construct ($is _sington=false, $user = ' nobody ', $output = '/dev/null ') {$this->is _sington= $is _sington; Whether to run a single case, a single run will create a unique PID $this the TMP directory->user= $user;/Set the running user by default nobody $this->output= $output; 
  Set the output of the place $this->checkpcntl (); //Check if the environment supports PCNTL support public Function checkpcntl () {if (! function_exists (' Pcntl_signal_dispatch ')) {// 
      PHP < 5.3 uses ticks to handle signals instead of Pcntl_signal_dispatch//call Sighandler only every 
    DECLARE (ticks = 10); }//Make sure PHP has support for Pcntl if (! function_exists (' pcntl_signal ')) {$message = ' php doe s not appear to is compiled with the pcntl extension. This is neccesary foR Daemonization '; 
      $this->_log ($message); 
    throw new Exception ($message); 
    //Signal processing pcntl_signal (sigterm, Array (__class__, "Signalhandler"), false); 
    Pcntl_signal (SIGINT, Array (__class__, "Signalhandler"), false); 
  
    Pcntl_signal (Sigquit, Array (__class__, "Signalhandler"), false); 
      Enable PHP 5.3 Garbage Collection if (function_exists (' gc_enable ')) {gc_enable (); 
    $this->gc_enabled = gc_enabled (); 
    }//Daemon program Public Function daemonize () {Global $stdin, $stdout, $stderr; 
  
    Global $argv; 
  
    Set_time_limit (0); 
    Only allow to run if (Php_sapi_name ()!= "cli") {die ("only run in command line mode\n") under the CLI; }//can only run if ($this->is_sington==true) {$this->pid_file = $this->info_dir. "/". __class__. "_" . substr (basename ($argv [0]), 0,-4). 
      ". pid"; 
    $this->checkpidfile (); } umask (0); Clear the file Mask 0 if (pcntl_fork ()!= 0) {//is the parent process, the parent process exits exit (); 
    Posix_setsid ()//Set new session leader, break out of terminal if (pcntl_fork ()!= 0) {//Is the first child process, end first subprocess exit (); } chdir ("/"); 
  
    Changing working directory $this->setuser ($this->user) or Die ("Cannot change owner"); 
    Closes the Open file descriptor 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 (); //--detect if the PID already exists public function checkpidfile () {if (!file_exists ($this->pid_file)) {Retu 
    RN 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); //----Create PID 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); 
    }//Set user Public function SetUser ($name) {$result = False to run; 
    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; //Signal processing function Public Function Signalhandler ($signo) {switch ($signo) {//user-defined signal case SIGUSR1:/ 
        /busy if ($this->workers_count < $this->workers_max) {$pid = Pcntl_fork (); 
        if ($pid > 0) {$this->workers_count + +;}} break; Child process End Signal Case Sigchld:while (($pid =pcntl_waitpid ( -1, $status, Wnohang)) > 0) {$this->wor 
        Kers_count--; 
      } break; 
      Interrupt process Case Sigterm:case sighup:case sigquit: $this->terminate = true; 
      Break 
    Default:return false; }/** * START process * $count the number of processes to open * * Public function start ($count =1) {$this->_log ("Daemon p 
    Rocess is running now "); Pcntl_signal (SIGCHLD, Array (__class__, "Signalhandler"), false); 
  
        If worker die, minus children num 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) {      This symbol represents the recovery system's default processing of signals (Sigterm, SIG_DFL) pcntl_signal; 
        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); }//The entire process exits 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); //Add work instance, currently only supports single job job 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 ("You must add a function to run!") 
    "); 
  
  } $this->jobs= $jobs; //log processing Private function _log ($message) {printf ("%s\t%d\t%d\t%s\n", Date ("C"), Posix_getpid (), Posix_getppid () 
  , $message); 
}//Call Method 1 $daemon =new Daemoncommand (true); 
$daemon->daemonize (); 
  
  
  
  
$daemon->start (2);//Open 2 sub processes work work (); 
Call Method 2 $daemon =new Daemoncommand (true); 
$daemon->daemonize (); $daemon->addjobs (' function ' => ' work ', ' argv ' => ', ' Runtime ' =>1000));//function the function to run. 
argv run the parameters of the function, runtime run the number of times $daemon->start (2);//Open 2 Sub processes work//specific function of the implementation function work () {echo "Test 1";  }?>

The above is about the PHP daemon related to the introduction, I hope to help you learn.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.