How to write the PHP daemon (Daemon), daemon Daemon
A daemon (Daemon) is a special process that runs in the background. It is independent of the control terminal and periodically performs some sort of task or waits to handle certain occurrences. Daemons are a very useful process. PHP can also implement the Daemon function.
first, the basic concept
Process:Each process has a parent process, the child process exits, and the parent process can get the status of the child process exit.
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. Running in the background
To avoid suspending the control terminal, put the daemon into the background. The method is to call fork in the process to terminate the parent process, allowing 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 terminal, logon session and process group
It is necessary to introduce the relationship between the process and the control terminal in Linux, 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 of the creation process. Control terminals, logon sessions and process groups are usually inherited from the parent process. Our aim is to get rid of them so that they are not affected by them. The method is based on the 1th, call Setsid () to make the process a conversation leader: Posix_setsid ();
Description: The Setsid () call failed when the process was the session leader. But the 1th has ensured that the process is not a 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. Due to the exclusivity of the session process to the control terminal, the process is disconnected from the control terminal at the same time.
3. Disable process re-opening control terminal
Now, the process has become a session leader without terminal. But it can be re-applied to open a control terminal. You can prevent a process from reopening the control terminal by making the process no longer a session leader: if ($pid =pcntl_fork ()) exit (0);//End first child process, second child process continue (second child process is no longer a conversation 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 where 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 and output with error display.
5. Change the current working directory
The file system in which the working directory resides cannot be unloaded while the process is active. It is generally necessary to change the working directory to the root directory. For processes that require dump cores, the process that writes the log changes the working directory to a specific directory such as ChDir ("/")
6. Resetting the 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, the file creation mask is cleared: umask (0);
7. Handling SIGCHLD Signals
Processing SIGCHLD signals is not a must. However, for some processes, in particular, server processes often generate child processes to process requests when requests arrive. If the parent process does not wait for the child process to end, the child process becomes a zombie process (zombie) and thus consumes system resources. If the parent process waits for the child process to end, it increases the burden on the parent process and affects the concurrency performance of the server process. The operation of the SIGCHLD signal can be easily set to Sig_ign under Linux. Signal (sigchld,sig_ign);
This way, the kernel does not spawn a zombie process at the end of the child process. Unlike BSD4, the BSD4 must explicitly wait for the child process to end before releasing the zombie process. Refer to the Linux signal Description list for signal issues
Third, 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 process public function __construct ($is _sington=false, $user = ' nobody ', $output = "/dev/null") {$this->is_sin gton= $is _sington; If a singleton runs, a single run will establish a unique PID $this->user= $user in the TMP directory;//set run user by default nobody $this->output= $output; Set the output Place $this->checkpcntl (); }//Check whether the environment supports PCNTL 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 ticks DECLARE (ticks = 10); }//Make sure PHP have support for Pcntl if (! function_exists (' pcntl_signal ')) {$message = ' PHP does no T appear to is compiled with the pcntl extension. This was 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 public Function daemonize () {Global $stdin, $stdout, $stderr; Global $argv; Set_time_limit (0); Only allow to run if (php_sapi_name ()! = "CLI") {die ("just run in command line mode\n") below the CLI; }//can only run an 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 up a new session groupLong, out-of-terminal if (pcntl_fork ()! = 0) {//Is the first child process, ending the first child process exit (); } chdir ("/"); Change the working directory $this->setuser ($this->user) or Die ("Cannot changes owner"); Close 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 (); }}//--detects if the PID already exists public function checkpidfile () {if (!file_exists ($this->pid_file)) {return 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 Run user Public function SetUser ($name) {$result = false; 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->worker S_cOunt--; } break; Interrupt process Case Sigterm:case sighup:case sigquit: $this->terminate = true; Break Default:return false; }}/** * START process * $count The number of processes ready to open */Public Function start ($count =1) {$this->_log ("daemon process is Running Now "); Pcntl_signal (SIGCHLD, Array (__class__, "Signalhandler"), false); If worker die, minus children num while (true) {if (function_exists (' Pcntl_signal_dispatch ')) {PCN Tl_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 Pcntl_signal (SIGTERM, SIG_DFL); 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 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 (); Call Method 2 $daemon =new Daemoncommand (true); $daemon->daemonize (); $daemon->addjobs (Array (' function ' = ' work ', ' argv ' = ' = ', ' Runtime ' =>1000),//function function to run, argv the parameters of the run function, the number of runtime runs $daemon->start (2),//Open 2 sub-processes work//specific functions of the implementation function works () {echo "Test 1";}?>
The above is about the PHP daemon related to the introduction, I hope that everyone's learning has helped.
Articles you may be interested in:
- PHP daemon plus linux command nohup implementation tasks executed once per second
- An overview of the implementation and optimization of PHP program-level Daemons
- PHP implementation of multi-process parallel operation of the detailed (can do daemon)
- Shell scripts are shared as daemon instances that ensure that PHP scripts do not hang out
- PHP Advanced Programming Example: Writing Daemons
- PHP Daemon Instance
- How PHP processes the process as a daemon
- PHP Extender Implementation Daemon
- Share the PHP daemon class
http://www.bkjia.com/PHPjc/1086643.html www.bkjia.com true http://www.bkjia.com/PHPjc/1086643.html techarticle How to write the PHP daemon (Daemon), daemon Daemon Daemon (Daemon) is a special process running in the background. It is independent of the control terminal and periodically performs some sort of task ...