This article is to share the content of the PHP implementation of the system programming of the Guardian process, has a certain reference value, the need for friends can refer to
(a) process groups, sessions, control terminals, control processes and other concepts
process Groups : Each process has a process group that belongs to it, the process group has a process team leader, and the process group ID is the process number of the process leader, so determine if a process is the leader of the process group, Just compare whether the incoming title is equal to its process group ID, PHP can use the function posix_getpgrp () to get the process group ID of the current process, and use Posix_getpid () to get the process number of the current process.
<?phpfunction Isgroupleader () { return posix_getpgrp () = = Posix_getpid (); $pid = Pcntl_fork (); if ($pid = = 0) { echo ' sub-process: '. Php_eol;} ElseIf ($pid > 0) { sleep (2); Echo ' Parent process: '. Php_eol;} echo "Current process group GID:". Posix_getpgrp (). Php_eol;echo "Current process number PID:". Posix_getpid (). Php_eol;if (Isgroupleader ()) { echo ' is a process group leader '. Php_eol;} else { echo ' is not a process group leader '. Php_eol;}
The above routines will output:
Child process: Current Process Group gid:15827 current process number pid:15828is not a process group leader parent process: Current Process Group gid:15827 current process number Pid:15827is a processes group leader
session : A session is a collection of process groups, a process group in the session is the conversation leader (session leader), the session ID is the session leader of the process group id,php can use the function posix_getsid (int $ PID) to get the session ID of the specified process, or you can use function Posix_setsid () to create a new session that is the session leader for a new session, which successfully returns the newly created conversation ID, or returns 1 on failure, note that the call in Linux the process of the POSIX_SETSID () function cannot be a process leader , otherwise the call fails because a process in a process group cannot span multiple sessions at the same time .
A description of the SETSID documentation in Linux:
Setsid () creates a new session if the calling process is not a process group leader. The calling process is the leader of the new session, the process group leader of the new process group, and have no CO Ntrolling TTY. The process group ID and session ID of the The calling process is set to the PID of the calling process. The calling process is the only process in this new process group and the new session.
<?phpfunction Isgroupleader () { return posix_getpgrp () = = Posix_getpid (); echo "Current session ID:". Posix_getsid (0). Php_eol; Pass 0 means get session idif (Isgroupleader ()) { echo "current process is process leader \ n";} $ret = Posix_setsid (); Create a new session var_dump ($ret); Because the current process is the leader of the process, 1 is returned here, indicating that the call failed
The above routines will output:
Current session id:13000 Current process is process leader Int (-1)
So how do I create a new session, and we notice that the child process is not the process leader after a child process has been created with pcntl_fork (), so the child process can be used to create the newly created sessions.
<?phpfunction Isgroupleader () { return posix_getpgrp () = = Posix_getpid (); echo "Current process belongs to session ID:". Posix_getsid (0). php_eol; $pid = Pcntl_fork (), if ($pid > 0) { exit (0);//Let Parent process exit}elseif ($pid = = 0) { if (Isgroupleader ()) { echo "is process group leader \ n"; } else { echo "is not a process group leader \ n"; } echo "Process group ID:". Posix_getpgrp (). Php_eol; echo "process number pid:". Posix_getpid (). Php_eol; $ret = Posix_setsid (); Var_dump ($ret); echo "Current process belongs to session ID:". Posix_getsid (0). Php_eol;}
The above routines will output:
The current process belongs to the session Id:13000[root@localhost php]# is not the process group leader Process Group id:15856 process number Pid:15857int (15857) The session to which the current process belongs id:15857
A new session was successfully created with the child process.
control terminal and control process : (terminal is the general name of all input, such as keyboard, mouse, monitor is a terminal) A session can have a control terminal, a control terminal is a session exclusive. The session has just been created with no control terminal, but the session leader can request to open a terminal, if this terminal is not the control terminal of other sessions, then the terminal will become the control terminal of the session, the conversation leader is called the control process.
Under Linux to determine whether a session has a control terminal, we can try to open a special file/dev/tty, he points to the real control terminal, if the open successful description of the control terminal, and vice versa there is no control terminal.
<?phpfunction Isgroupleader () { return posix_getpgrp () = = Posix_getpid (); $pid = Pcntl_fork (), if ($pid > 0) { sleep (1); $fp = fopen ("/dev/tty", "RB"); if ($fp) { echo "parent process session". Posix_getsid (0). "Owning control terminal \ n"; } else { echo ' parent process session '. Posix_getsid (0). "Does not own control terminal \ n"; } Exit (0); Let the parent process exit}elseif ($pid = = 0) { if (Isgroupleader ()) { echo "is the process group leader \ n"; } else { echo "is not the process group leader \ n";
} $ret = Posix_setsid (); Var_dump ($ret); $fp = fopen ("/dev/tty", "RB"); if ($fp) { echo "child process session". Posix_getsid (0). "Owning control terminal \ n"; } else { echo "child process session". Posix_getsid (0). "Does not own control terminal \ n";} }
The example Cheng Zi process creates a new session, and the parent-child process tries to open the file/dev/tty, and the routine output is as follows:
Not process group leader Int (15906) PHP Warning: fopen (/dev/tty): Failed to open stream:no such device or address in/root/php/setsid.ph P on line 30warning:fopen (/dev/tty): Failed to open stream:no such device or address in/root/php/setsid.php on line 30 sub Process session 15906 does not have control terminal parent process session 13000 owns control terminal
Generate Sighup Signal
1, when a session loses control terminal, the kernel will send a SIGHUP signal to the control process of the session, and usually the control process of the session is the shell process, the shell receives a SIGHUP signal, Sends a SIGHUP signal to all process groups created by it (foreground or background process Group), and then exits, and the process receives a SIGHUP signal by default, which is to exit the process, and the process can also customize the signal processing or ignore it.
2. In addition, when the control process terminates, the kernel also sends SIGHUP signals to all members of the terminal's foreground process group.
<?php$callback = function ($signo) { $sigstr = ' unkown signal '; Switch ($signo) {case SIGINT: $sigstr = ' SIGINT '; break; Case SIGHUP: $sigstr = ' SIGHUP '; break; Case SIGTSTP: $sigstr = ' SIGTSTP '; break; } File_put_contents ("Daemon.txt", "catch signal $sigstr \ n", file_append);}; Pcntl_signal (SIGINT, $callback);p cntl_signal (SIGHUP, $callback);p cntl_signal (SIGTSTP, $callback); while (1) { Sleep (+); Pcntl_signal_dispatch ();}
Using PHP sighup.php to run the program, and then directly shut down the terminal, re-login to the shell, you will find that the program is still running, the Daemon.txt file will record the captured Sighup signal.
[Root@localhost php]# cat daemon.txt catch signal sighup[root@localhost php]# PS aux | grep sighup.php root 18438 0.0 0.4 191600 8996? S 16:48 0:00 php sighup.phproot 18443 0.0 0.0 103328 896 pts/0 s+ 16:53 0:00 grep sighup.php
At the same time, Linux provides a nohup command that allows the process to ignore all sighup signals, such as
[Root@localhost php]# nohup php sighup.php nohup: Ignore input and append output to ' nohup.out '
(ii) standard input, standard output, standard error Output
PHP has three default open file handle Stdin,stdout, STDERR corresponding to the above three file descriptors, and since the standard input and output is terminal-related, for the daemon is not much use, can be closed directly, but the direct shutdown may cause a problem, Take a look at the code below
<?phpfclose (STDOUT); $fp = fopen ("Stdout.log", "a"); echo "Hello world\n";
When running the above code, the screen does not output echo information, but writes to the open file, because the corresponding file descriptor is released after closing the stdout file handle, and the Linux open file always uses the smallest available file descriptor. So the file descriptor now points to the fopen open file, which causes the information that was originally written to the standard output to now be written in the file. To avoid this bizarre behavior, we can immediately open the black hole file/dev/null provided by Linux after closing these three file handles, for example:
<?phpfclose (STDIN); fclose (STDOUT); fclose (STDERR); fopen ('/dev/null ', ' R '); fopen ('/dev/null ', ' W '); fopen ('/dev/ Null ', ' W '); $fp = fopen ("Stdout.log", "a"); echo "Hello world\n";
Above this routine to close Stdin,stdout, stderr immediately open/dev/null three times, so that the echo of the information will be directly written into the black hole, to avoid the strange problem of the previous appearance.
(iii) Other issues related to the preparation of the daemon
The process of writing daemons also involves working directory, file mask, signal processing, hot update, security start stop and so on, first left to everyone's own Baidu, and later to add to the free.
(iv) An example of a daemon process
<?php//because the process leader cannot create a session, fork a child process and let the parent process exit so that you can create a new session switch (Pcntl_fork ()) { case-1: exit ("fork Error"); break; Case 0: Break ; Default: exit (0);//Parent Process exit}posix_setsid (); Create a new session, detach from the original control terminal//fork again and let the parent process exit, the child process is no longer the session first process, so that it can never open a control terminal switch (Pcntl_fork ()) { case-1: exit ("fork Error "); break; Case 0: Break ; Default: exit (0);//parent process exit}//close standard input Output fclose (STDIN); fclose (STDOUT); fclose (STDERR); fopen ('/dev/null ', ' R '); fopen ('/dev/null ', ' W '); fopen ('/dev/null ', ' w ');//Switch working directory ChDir ('/');//Clear File Mask umask (0);//Because the kernel no longer generates a SIGHUP signal for the process, We can use this signal to implement the hot restart pcntl_signal (SIGHUP, function ($signo) { //reload config file, reopen log file, etc.}); for (;;) { pcntl_signal_dispatch (); Processing signal callbacks //Implementing business logic}
to be continue!