国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Home Backend Development PHP Tutorial What is a daemon? How to implement daemon in PHP?

What is a daemon? How to implement daemon in PHP?

Jun 23, 2021 pm 08:30 PM
php

A daemon is a special process that runs in the background and is used to perform specific system tasks. This article will take you through how to implement daemon in PHP and introduce what you need to pay attention to in programming.

What is a daemon? How to implement daemon in PHP?

PHP implementation daemon can be implemented through the pcntl and posix extensions.

Things that need to be noted in programming are:

  • Let the main process leave the terminal through the second pcntl_fork() and posix_setsid
  • #Pass
  • pcntl_signal() Ignore or handle SIGHUP signal
  • Multi-process programs need to pass twice
  • pcntl_fork() or pcntl_signal() Ignore the SIGCHLD signal to prevent the child process from becoming a Zombie process
  • Set the file permission mask through
  • umask() to prevent inheritance of file permissions The resulting permission impact function
  • redirects the
  • STDIN/STDOUT/STDERR of the running process to /dev/null or other streams
If you want to do better, you also need to pay attention to:

    If you start through root, change to a low-privilege user identity when running
  • Timely
  • chdir() Prevent operation error paths
  • Consider restarting multi-process programs regularly to prevent memory leaks

What is a daemon

The protagonist of the article

Daemon, the definition on Wikipedia is:

In a multi-tasking computer operating system, the daemon process (English: daemon, /?di?m?n/ or /?de?m?n/) is a computer program that executes in the background. Such programs will be initialized as processes. The names of daemon programs usually end with the letter "d": for example, syslogd refers to the daemon that manages system logs.

Usually, the daemon process does not have any existing parent process (that is, PPID=1), and is directly under init in the UNIX system process hierarchy. A daemon program usually makes itself a daemon by running fork on a child process, and then terminating its parent process immediately so that the child process can run under init. This method is often called "shelling."

Advanced Programming in UNIX Environment (Second Edition) (hereinafter referred to as APUE) There is a cloud in Chapter 13:

Daemon processes have also become The daemon process is a process with a long life cycle. They are often started when the system boots and terminate only when the system is shut down. Because they don't have a controlling terminal, they are said to run in the background.

It is noted here that daemon has the following characteristics:

    No terminal
  • Running in the background
  • The parent process pid is 1
If you want to view the running daemon process, you can view it through

ps -ax or ps -ef, where -x means it will be listed There is no process controlling the terminal.

Implementation concerns

Second fork and setsid

fork system call

fork The system call is used to copy a process that is almost identical to the parent process. The difference between the newly generated child process and the parent process is that it has a different pid and a different According to the code logic implementation of the memory space, the parent and child processes can complete the same work or different tasks. The child process inherits resources such as file descriptors from the parent process.

The

pcntl extension in PHP implements the pcntl_fork() function, which is used to fork a new process in PHP.

setsid system call

setsid The system call is used to create a new session and set the process group id.

There are several concepts here:

Session, Process Group.

In Linux, user login generates a session. A session contains one or more process groups, and a process group contains multiple processes. Each process group has a session leader, and its pid is the group id of the process group. Once the process leader opens a terminal, this terminal is called the controlling terminal. Once an exception occurs in the control terminal (disconnection, hardware error, etc.), a signal will be sent to the process group leader.

Background running programs (such as shell execution instructions ending with

&) will also be killed after the terminal is closed, that is, the SIGHUP issued when the control terminal is disconnected is not handled properly. signal, and the default behavior of SIGHUP signal for a process is to exit the process.

Callsetsid After the system call, the current process will create a new process group. If the terminal is not opened in the current process, then there will be no control terminal in this process group, and there will be no control terminal. There will be a problem of killing the process by closing the terminal.

The posix extension in PHP implements the posix_setsid() function, which is used to set a new process group in PHP.

Orphan process

The parent process exits before the child process, and the child process will become an orphan process.

The init process will adopt the orphan process, that is, the ppid of the orphan process becomes 1.

The role of secondary fork

First of all, the setsid system call cannot be called by the process group leader and will return -1.

The sample code for the second fork operation is as follows:

$pid1 = pcntl_fork();

if ($pid1 > 0) {
    exit(0);
} else if ($pid1 < 0) {
    exit("Failed to fork 1\n");
}

if (-1 == posix_setsid()) {
    exit("Failed to setsid\n");
}

$pid2 = pcntl_fork();

if ($pid2 > 0) {
    exit(0);
} else if ($pid2 < 0) {
    exit("Failed to fork 2\n");
}

Assume that we execute the application in the terminal and the process is a. The first fork will generate a child process b. If the fork is successful, Parent process a exits. b As an orphan process, it is hosted by the init process.

At this time, process b is in process group a, and process b calls posix_setsid to request the generation of a new process group. After the call is successful, the current process group becomes b.

At this time, process b has actually separated from any control terminal. Routine:

<?php

cli_set_process_title(&#39;process_a&#39;);

$pidA = pcntl_fork();

if ($pidA > 0) {
    exit(0);
} else if ($pidA < 0) {
    exit(1);
}

cli_set_process_title(&#39;process_b&#39;);

if (-1 === posix_setsid()) {
    exit(2);
}

while(true) {
    sleep(1);
}

After executing the program:

?  ~ php56 2fork1.php
?  ~ ps ax | grep -v grep | grep -E &#39;process_|PID&#39;
  PID TTY      STAT   TIME COMMAND
28203 ?        Ss     0:00 process_b

From the results of ps, the TTY of process_b Has it become ? , that is, there is no corresponding control terminal.

When the code reaches this point, it seems that the function has been completed. process_b has not been killed after closing the terminal, but why is there a second fork operation?

An answer on StackOverflow is well written:

The second fork(2) is there to ensure that the new process is not a session leader , so it won't be able to (accidentally) allocate a controlling terminal, since daemons are not supposed to ever have a controlling terminal.

This is to prevent the actual working process from actively associating or The control terminal is accidentally associated. The new process generated after forking again cannot apply for association with the control terminal because it is not the process group leader.

To sum up, the function of secondary fork and setsid is to generate a new process group and prevent the working process from being associated with the control terminal.

SIGHUP signal handling

The default action of a process receiving the SIGHUP signal is to terminate the process.

And SIGHUP will be issued under the following circumstances:

  • The control terminal is disconnected, and SIGHUP is sent to the process group leader
  • Process group When the group leader exits, SIGHUP will be sent to the foreground process in the process group
  • SIGHUP is often used to notify the process to reload the configuration file (mentioned in APUE, the daemon is considered unlikely to receive it because it does not have a control terminal) This is a signal, so we choose to reuse it)

Since the actual working process is not in the foreground process group, and the leader of the process group has exited and does not control the terminal, of course there will be no processing under normal circumstances. Problem, however, in order to prevent the process from exiting due to the accidental receipt of SIGHUP, and in order to follow the conventions of daemon programming, this signal should still be processed.

Zombie process processing

What is the Zombie process

Simply put, the child process first When the parent process exits, the parent process does not call the wait system call processing, and the process becomes a Zombie process.

When the child process exits before the parent process, it will send the SIGCHLD signal to the parent process. If the parent process does not handle it, the child process will also become a Zombie process.

Zombie processes will occupy the number of processes that can be forked. Too many zombie processes will result in the inability to fork new processes.

In addition, in the Linux system, a process whose ppid is the init process will be recycled and managed by the init process after it becomes a Zombie.

Zombie process processing

From the characteristics of the Zombie process, for multi-process daemons, this problem can be solved in two ways:

  • Parent process processing SIGCHLD Signal
  • Let the child process be taken over by init

Parent process processing signal Needless to say, register the signal processing callback function and call Recycling method is enough.

For the child process to be taken over by init, you can use the method of fork twice, so that the child process a from the first fork can then fork out the actual working process b, and let a exit first, so that b becomes Orphan process so that it can be hosted by the init process.

umask

umask will be inherited from the parent process, affecting the permissions to create files.

PHP Manual mentioned:

umask() sets PHP's umask to mask & 0777 and returns the original umask. When PHP is used as a server module, the umask is restored after each request.

If the umask of the parent process is not set properly, unexpected effects will occur when performing some file operations:

?  ~ cat test_umask.php
<?php
        chdir(&#39;/tmp&#39;);
        umask(0066);
        mkdir(&#39;test_umask&#39;, 0777);
?  ~ php test_umask.php
?  ~ ll /tmp | grep umask
drwx--x--x 2 root root 4.0K 8月  22 17:35 test_umask

所以,為了保證每一次都能按照預(yù)期的權(quán)限操作文件,需要置0 umask 值。

重定向0/1/2

這里的0/1/2分別指的是 STDIN/STDOUT/STDERR,即標(biāo)準(zhǔn)輸入/輸出/錯(cuò)誤三個(gè)流。

樣例

首先來(lái)看一個(gè)樣例:

上述代碼幾乎完成了文章最開始部分提及的各個(gè)方面,唯一不同的是沒(méi)有對(duì)標(biāo)準(zhǔn)流做處理。通過(guò) php not_redirect_std_stream_daemon.php 指令也能讓程序在后臺(tái)進(jìn)行。

sleep 的間隙,關(guān)閉終端,會(huì)發(fā)現(xiàn)進(jìn)程退出。

通過(guò) strace 觀察系統(tǒng)調(diào)用的情況:

?  ~ strace -p 6723
Process 6723 attached - interrupt to quit
restart_syscall(<... resuming interrupted call ...>) = 0
write(1, "1503417004\n", 11)            = 11
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
nanosleep({10, 0}, 0x7fff71a30ec0)      = 0
write(1, "1503417014\n", 11)            = -1 EIO (Input/output error)
close(2)                                = 0
close(1)                                = 0
munmap(0x7f35abf59000, 4096)            = 0
close(0)                                = 0

發(fā)現(xiàn)發(fā)生了 EIO 錯(cuò)誤,導(dǎo)致進(jìn)程退出。

原因很簡(jiǎn)單,即我們編寫的 daemon 程序使用了當(dāng)時(shí)啟動(dòng)時(shí)終端提供的標(biāo)準(zhǔn)流,當(dāng)終端關(guān)閉時(shí),標(biāo)準(zhǔn)流變得不可讀不可寫,一旦嘗試讀寫,會(huì)導(dǎo)致進(jìn)程退出。

信海龍的博文《一個(gè)echo引起的進(jìn)程崩潰》中也提到過(guò)類似的問(wèn)題。

解決方案

APUE 樣例

APUE 13.3中提到過(guò)一條編程規(guī)則(第6條):

某些守護(hù)進(jìn)程打開 /dev/null 時(shí)期具有文件描述符0、1和2,這樣,任何一個(gè)視圖讀標(biāo)準(zhǔn)輸入、寫標(biāo)準(zhǔn)輸出或者標(biāo)準(zhǔn)錯(cuò)誤的庫(kù)例程都不會(huì)產(chǎn)生任何效果。因?yàn)槭刈o(hù)進(jìn)程并不與終端設(shè)備相關(guān)聯(lián),所以不能在終端設(shè)備上顯示器輸出,也無(wú)從從交互式用戶那里接受輸入。及時(shí)守護(hù)進(jìn)程是從交互式會(huì)話啟動(dòng)的,但因?yàn)槭刈o(hù)進(jìn)程是在后臺(tái)運(yùn)行的,所以登錄會(huì)話的終止并不影響守護(hù)進(jìn)程。如果其他用戶在同一終端設(shè)備上登錄,我們也不會(huì)在該終端上見到守護(hù)進(jìn)程的輸出,用戶也不可期望他們?cè)诮K端上的輸入會(huì)由守護(hù)進(jìn)程讀取。

簡(jiǎn)單來(lái)說(shuō):

  • daemon 不應(yīng)使用標(biāo)準(zhǔn)流
  • 0/1/2 要設(shè)定成 /dev/null

例程中使用:

for (i = 0; i < rl.rlim_max; i++)
	close(i);

fd0 = open("/dev/null", O_RDWR);
fd1 = dup(0);
fd2 = dup(0);

實(shí)現(xiàn)了這一個(gè)功能。dup() (參考手冊(cè))系統(tǒng)調(diào)用會(huì)復(fù)制輸入?yún)?shù)中的文件描述符,并復(fù)制到最小的未分配文件描述符上。所以上述例程可以理解為:

關(guān)閉所有可以打開的文件描述符,包括標(biāo)準(zhǔn)輸入輸出錯(cuò)誤;
打開/dev/null并賦值給變量fd0,因?yàn)闃?biāo)準(zhǔn)輸入已經(jīng)關(guān)閉了,所以/dev/null會(huì)綁定到0,即標(biāo)準(zhǔn)輸入;
因?yàn)樽钚∥捶峙湮募枋龇麨?,復(fù)制文件描述符0到文件描述符1,即標(biāo)準(zhǔn)輸出也綁定到/dev/null;
因?yàn)樽钚∥捶峙湮募枋龇麨?,復(fù)制文件描述符0到文件描述符2,即標(biāo)準(zhǔn)錯(cuò)誤也綁定到/dev/null;復(fù)制代碼

開源項(xiàng)目實(shí)現(xiàn):Workerman

Workerman 中的 Worker.php 中的 resetStd() 方法實(shí)現(xiàn)了類似的操作。

/**
* Redirect standard input and output.
*
* @throws Exception
*/
public static function resetStd()
{
   if (!self::$daemonize) {
       return;
   }
   global $STDOUT, $STDERR;
   $handle = fopen(self::$stdoutFile, "a");
   if ($handle) {
       unset($handle);
       @fclose(STDOUT);
       @fclose(STDERR);
       $STDOUT = fopen(self::$stdoutFile, "a");
       $STDERR = fopen(self::$stdoutFile, "a");
   } else {
       throw new Exception(&#39;can not open stdoutFile &#39; . self::$stdoutFile);
   }
}

Workerman 中如此實(shí)現(xiàn),結(jié)合博文,可能與 PHP 的 GC 機(jī)制有關(guān),對(duì)于 fd 0 1 2來(lái)說(shuō),PHP 會(huì)維持對(duì)這三個(gè)資源的引用計(jì)數(shù),在直接 fclose 之后,會(huì)使得這幾個(gè) fd 對(duì)應(yīng)的資源類型的變量引用計(jì)數(shù)為0,導(dǎo)致觸發(fā)回收。所需要做的就是將這些變量變?yōu)槿肿兞?,保證引用的存在。

推薦學(xué)習(xí):《PHP視頻教程

The above is the detailed content of What is a daemon? How to implement daemon in PHP?. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undress AI Tool

Undress AI Tool

Undress images for free

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to get the current session ID in PHP? How to get the current session ID in PHP? Jul 13, 2025 am 03:02 AM

The method to get the current session ID in PHP is to use the session_id() function, but you must call session_start() to successfully obtain it. 1. Call session_start() to start the session; 2. Use session_id() to read the session ID and output a string similar to abc123def456ghi789; 3. If the return is empty, check whether session_start() is missing, whether the user accesses for the first time, or whether the session is destroyed; 4. The session ID can be used for logging, security verification and cross-request communication, but security needs to be paid attention to. Make sure that the session is correctly enabled and the ID can be obtained successfully.

PHP get substring from a string PHP get substring from a string Jul 13, 2025 am 02:59 AM

To extract substrings from PHP strings, you can use the substr() function, which is syntax substr(string$string,int$start,?int$length=null), and if the length is not specified, it will be intercepted to the end; when processing multi-byte characters such as Chinese, you should use the mb_substr() function to avoid garbled code; if you need to intercept the string according to a specific separator, you can use exploit() or combine strpos() and substr() to implement it, such as extracting file name extensions or domain names.

How do you perform unit testing for php code? How do you perform unit testing for php code? Jul 13, 2025 am 02:54 AM

UnittestinginPHPinvolvesverifyingindividualcodeunitslikefunctionsormethodstocatchbugsearlyandensurereliablerefactoring.1)SetupPHPUnitviaComposer,createatestdirectory,andconfigureautoloadandphpunit.xml.2)Writetestcasesfollowingthearrange-act-assertpat

How to split a string into an array in PHP How to split a string into an array in PHP Jul 13, 2025 am 02:59 AM

In PHP, the most common method is to split the string into an array using the exploit() function. This function divides the string into multiple parts through the specified delimiter and returns an array. The syntax is exploit(separator, string, limit), where separator is the separator, string is the original string, and limit is an optional parameter to control the maximum number of segments. For example $str="apple,banana,orange";$arr=explode(",",$str); The result is ["apple","bana

JavaScript Data Types: Primitive vs Reference JavaScript Data Types: Primitive vs Reference Jul 13, 2025 am 02:43 AM

JavaScript data types are divided into primitive types and reference types. Primitive types include string, number, boolean, null, undefined, and symbol. The values are immutable and copies are copied when assigning values, so they do not affect each other; reference types such as objects, arrays and functions store memory addresses, and variables pointing to the same object will affect each other. Typeof and instanceof can be used to determine types, but pay attention to the historical issues of typeofnull. Understanding these two types of differences can help write more stable and reliable code.

Using std::chrono in C Using std::chrono in C Jul 15, 2025 am 01:30 AM

std::chrono is used in C to process time, including obtaining the current time, measuring execution time, operation time point and duration, and formatting analysis time. 1. Use std::chrono::system_clock::now() to obtain the current time, which can be converted into a readable string, but the system clock may not be monotonous; 2. Use std::chrono::steady_clock to measure the execution time to ensure monotony, and convert it into milliseconds, seconds and other units through duration_cast; 3. Time point (time_point) and duration (duration) can be interoperable, but attention should be paid to unit compatibility and clock epoch (epoch)

How to pass a session variable to another page in PHP? How to pass a session variable to another page in PHP? Jul 13, 2025 am 02:39 AM

In PHP, to pass a session variable to another page, the key is to start the session correctly and use the same $_SESSION key name. 1. Before using session variables for each page, it must be called session_start() and placed in the front of the script; 2. Set session variables such as $_SESSION['username']='JohnDoe' on the first page; 3. After calling session_start() on another page, access the variables through the same key name; 4. Make sure that session_start() is called on each page, avoid outputting content in advance, and check that the session storage path on the server is writable; 5. Use ses

How does PHP handle Environment Variables? How does PHP handle Environment Variables? Jul 14, 2025 am 03:01 AM

ToaccessenvironmentvariablesinPHP,usegetenv()orthe$_ENVsuperglobal.1.getenv('VAR_NAME')retrievesaspecificvariable.2.$_ENV['VAR_NAME']accessesvariablesifvariables_orderinphp.iniincludes"E".SetvariablesviaCLIwithVAR=valuephpscript.php,inApach

See all articles