이 기사는 주로 PHP7을 사용하여 데몬 프로세스를 구현하는 방법에 대해 설명합니다. 관심 있는 친구는 이에 대해 배울 수 있습니다.
멀티 태스킹 컴퓨터 운영 체제에서 데몬 은 백그라운드에서 실행되는 컴퓨터 프로그램입니다. 이러한 프로그램은 프로세스로 초기화됩니다. 데몬 프로그램의 이름은 일반적으로 문자 "d"로 끝납니다. 예를 들어 syslogd는 시스템 로그를 관리하는 데몬을 나타냅니다.
데몬 프로그램은 항상 실행되는 서버 프로그램으로 데몬 프로세스라고도 합니다. 일반적으로 시스템의 백그라운드에서 실행되며 제어 터미널이 없으며 포그라운드와 상호 작용하지 않습니다. 일반적으로 데몬 프로그램은 시스템 서비스로 사용됩니다. 데몬은 일반적으로 시스템이 시작된 후에 실행되고 시스템이 종료될 때 종료되는 장기 실행 프로세스입니다. 일반적으로 데몬 프로그램은 제어 터미널이 없고 포그라운드의 사용자와 상호 작용할 수 없기 때문에 백그라운드에서 실행됩니다. 데몬 프로그램은 일반적으로 클라이언트 프로그램이 통신할 때까지 기다리는 서비스 프로그램으로 사용됩니다. 또한 실행 중인 데몬 프로그램을 데몬 프로세스라고 부릅니다.
일반적으로 데몬 프로세스에는 기존 상위 프로세스(예: PPID=1)가 없으며 UNIX 시스템 프로세스 계층의 init 바로 아래에 있습니다. 데몬 프로그램은 일반적으로 다음과 같은 방법으로 자신을 데몬으로 만듭니다. 하위 프로세스에서 실행 fork한 다음 상위 프로세스를 즉시 종료하여 하위 프로세스가 init에서 실행될 수 있도록 합니다. 이 방법을 흔히 "쉘링"이라고 합니다.
시스템은 일반적으로 시작 시 데몬 프로세스를 시작합니다. 데몬은 특정 작업을 통해 네트워크 요청, 하드웨어 활동 또는 다른 응용 프로그램의 기타 요청에 응답하기 위한 지원을 제공합니다. 데몬은 하드웨어(예: 일부 Linux 시스템의 devfsd)를 구성하고 예약된 작업(예: cron)을 실행하며 기타 작업을 실행할 수도 있습니다. 각 프로세스에는 상위 프로세스가 있습니다. 하위 프로세스가 종료되면 상위 프로세스는 하위 프로세스의 종료 상태를 얻을 수 있습니다.
간단히 말하면 데몬 프로세스는 터미널 없이 백그라운드에서 실행될 수 있는 프로세스입니다. 예를 들어 apache나 mysql과 같은 서비스가 시작된 후 수행됩니다. 메모리에 데몬 프로세스로 배치됩니다. 데몬은 사용자가 직접 조작하지 않고 백그라운드에서 실행되는 애플리케이션입니다. 데몬의 예로는 Cron 및 MySQL이 있습니다. PHP 데몬을 사용하는 것은 매우 간단하며 PHP 4.1 이상의 컴파일 매개변수가 필요합니다: --enable-pcntl
백그라운드에서 실행해야 하는 시간 소모적인 작업이 있는 경우: mysql을 모두 입력하세요. 캐시 예열을 위해 user 테이블에 있는 2천만 명의 사용자를 모두 redis로 가져오기 때문에 이 작업은 한동안 끝나지 않을 것으로 추정됩니다. 이때 시스템에서 데몬으로 실행하려면 php 스크립트를 작성해야 하며, 이를 수행하기 위한 작업이 필요합니다. 종료 후 자동으로 시작됩니다.
명령 뒤에 & 기호를 추가합니다. 터미널이 종료되면 정상 종료이든 비정상 종료이든 터미널이 닫힐 때 PHP 프로세스가 종료됩니다. 둘째, 코드에 echo 또는 print_r과 같은 출력 텍스트가 있으면 출력됩니다. 현재 터미널 창으로 이동합니다.
3. 확장
프로그래밍에서 주의해야 할 사항은 다음과 같습니다. daemon有如下特征: 想要查看运行中的守护进程可以通过 fork 系统调用用于复制一个与父进程几乎完全相同的进程,新生成的子进程不同的地方在于与父进程有着不同的 pid 以及有不同的内存空间,根据代码逻辑实现,父子进程可以完成一样的工作,也可以不同。子进程会从父进程中继承比如文件描述符一类的资源。 PHP 中的 setsid 系统调用则用于创建一个新的会话并设定进程组 id。这里有几个概念: 在 Linux 中,用户登录产生一个会话(Session),一个会话中包含一个或者多个进程组,一个进程组又包含多个进程。每个进程组有一个组长(Session Leader),它的 pid 就是进程组的组 id。进程组长一旦打开一个终端,这一个终端就被称为控制终端。一旦控制终端发生异常(断开、硬件错误等),会发出信号到进程组组长。 后台运行程序(如 shell 中以 调用 setsid 系统调用之后,会让当前的进程新建一个进程组,如果在当前进程中不打开终端的话,那么这一个进程组就不会存在控制终端,也就不会出现因为关闭终端而杀死进程的问题。 PHP 中的 首先, 를 처리하려면 다중 프로세스 프로그램이 데몬은 다음과 같은 특징을 가지고 있습니다: 터미널 없음백그라운드에서 실행 假定我们在终端中执行应用程序,进程为 a,第一次 fork 会生成子进程 b,如果 fork 成功,父进程 a 退出。b 作为孤儿进程,被 init 进程托管。 此时,进程 b 处于进程组 a 中,进程 b 调用 此时进程 b 事实上已经脱离任何的控制终端,例程: 执行程序之后: 重新打开一个shell窗口,效果一样,都在呢 从 ps 的结果来看,process_b 的 TTY 已经变成了 代码走到这里,似乎已经完成了功能,关闭终端之后 process_b 也没有被杀死,但是为什么还要进行第二次 fork 操作呢? StackOverflow 上的一个回答写的很好: 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. 这是为了防止实际的工作的进程主动关联或者意外关联控制终端,再次 fork 之后生成的新进程由于不是进程组组长,是不能申请关联控制终端的。 综上,二次 fork 与 setsid 的作用是生成新的进程组,防止工作进程关联控制终端。 写一个demo测试下 Window 下跑回直接抛出异常 Linux 下执行,输出结果 相关教程:PHP视频教程pcntl
与 posix
pcntl_fork()
및 posix_setsid
를 통해 터미널에서 기본 프로세스를 두 번 전달합니다. pcntl_fork()
以及 posix_setsid
让主进程脱离终端pcntl_signal()
忽略或者处理 SIGHUP
信号pcntl_fork()
或者 pcntl_signal()
忽略 SIGCHLD
信号防止子进程变成 Zombie 进程umask()
设定文件权限掩码,防止继承文件权限而来的权限影响功能STDIN/STDOUT/STDERR
重定向到 /dev/null
或者其他流上
ps -ax
或者 ps -ef
查看,其中 -x
表示会列出没有控制终端的进程。fork 系统调用
pcntl
扩展中实现了 pcntl_fork()
函数,用于在 PHP 中 fork 新的进程。setsid 系统调用
会话
,进程组
。&
结尾执行指令)在终端关闭之后也会被杀死,就是没有处理好控制终端断开时发出的SIGHUP
信号,而SIGHUP
信号对于进程的默认行为则是退出进程。posix
扩展中实现了 posix_setsid()
函数,用于在 PHP 中设定新的进程组。二次 fork 的作用
setsid
pcntl_signal()
무시하거나 SIGHUP
신호pcntl_fork()
또는 pcntl_signal()
을 두 번 통과해야 합니다. SIGCHLD
무시 신호는 하위 프로세스가 좀비 프로세스가 되는 것을 방지합니다umask()
를 통해 파일 권한 마스크를 설정하여 파일 권한이 함수에 영향을 주지 않습니다 li>실행 중인 프로세스의 STDIN/STDOUT/STDERR
를 /dev/null
또는 다른 스트림으로 리디렉션ps -ax
또는 ps -ef
를 통해 볼 수 있습니다. -x
는 제어 터미널이 프로세스로 나열되지 않음을 의미합니다. 🎜🎜🎜fork 시스템 호출🎜
🎜🎜 포크 시스템 호출은 상위 프로세스와 거의 동일한 프로세스를 복사하는 데 사용됩니다. 새로 생성된 하위 프로세스의 차이점입니다. 프로세스 및 상위 프로세스는 코드 논리 구현에 따라 서로 다른 PID와 서로 다른 메모리 공간을 가지며 상위 프로세스와 하위 프로세스는 동일한 작업을 완료할 수도 있고 서로 다를 수도 있습니다. 하위 프로세스는 상위 프로세스로부터 파일 설명자와 같은 리소스를 상속받습니다. 🎜🎜🎜🎜PHP의 pcntl
확장은 PHP에서 새 프로세스를 포크하는 데 사용되는 pcntl_fork()
함수를 구현합니다. 🎜🎜🎜setsid 시스템 호출🎜
🎜🎜setsid 시스템 호출은 새 세션을 생성하고 프로세스 그룹 ID를 설정하는 데 사용됩니다. 여기에는 🎜세션
🎜, 🎜프로세스 그룹
🎜과 같은 몇 가지 개념이 있습니다. 🎜🎜🎜🎜 Linux에서는 사용자 로그인이 세션을 생성합니다. 세션에는 하나 이상의 프로세스 그룹이 포함되며 프로세스 그룹에는 여러 프로세스가 포함됩니다. 각 프로세스 그룹에는 그룹 리더(🎜Session Leader🎜)가 있으며, 해당 pid는 프로세스 그룹의 그룹 ID입니다. 프로세스 리더가 터미널을 열면 이 터미널을 제어 터미널이라고 합니다. 제어 터미널에서 예외(연결 끊김, 하드웨어 오류 등)가 발생하면 프로세스 그룹 리더에게 신호가 전송됩니다. 🎜🎜🎜🎜 백그라운드 실행 프로그램(예: 셸에서 &
로 끝나는 실행 명령)도 터미널이 닫힌 후에 종료됩니다. 즉, 제어 터미널이 실행될 때 발행되는 🎜SIGHUP입니다.
🎜 신호가 제대로 처리되지 않으며 프로세스에 대한 🎜SIGHUP
🎜 신호의 기본 동작은 프로세스를 종료하는 것입니다. 🎜🎜🎜setsid🎜 호출 시스템 호출 후 현재 프로세스는 새로운 프로세스 그룹, 현재 프로세스에서 터미널이 열리지 않으면 이 프로세스 그룹에는 제어 터미널이 없으며 터미널을 닫아 프로세스를 종료하는 문제가 없습니다. 🎜🎜🎜🎜PHP의 posix
확장은 PHP에서 새 프로세스 그룹을 설정하는 데 사용되는 posix_setsid()
함수를 구현합니다. 🎜🎜🎜The role of Secondary Fork🎜
🎜🎜먼저 setsid
시스템 호출은 프로세스에서 호출할 수 없습니다. 그룹 리더 -1을 반환합니다. 🎜🎜🎜🎜두 번째 포크 작업의 샘플 코드는 다음과 같습니다. 🎜🎜<span style="font-size: 16px;">$pid1 = pcntl_fork();
if ($pid1 > 0) {</span><br/><span style="font-size: 16px;"> // 父进程会得到子进程号,所以这里是父进程执行的逻辑
exit('parent process. 1'."\n");
} 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('parent process. 2'."\n");
} else if ($pid2 < 0) {
exit("Failed to fork 2\n");
}</span>
posix_setsid
要求生成新的进程组,调用成功后当前进程组变为 b。php fork2.php
parent process. 1
parent process. 2
cli_set_process_title('process_a');
$pidA = pcntl_fork();
if ($pidA > 0) {
exit(0);
} else if ($pidA < 0) {
exit(1);
}
cli_set_process_title('process_b');
if (-1 === posix_setsid()) {
exit(2);
}
while(true) {
sleep(1);
}
$ php cli-title.php
$ ps ax | grep -v grep | grep -E 'process_|PID'
PID TTY STAT TIME COMMAND
15725 ? Ss 0:00 process_b
?
,即没有对应的控制终端。<?php
// 第一次fork系统调用
$pid_A = pcntl_fork();
// 父进程 和 子进程 都会执行下面代码
if ($pid_A < 0) {
// 错误处理: 创建子进程失败时返回-1.
exit('A fork error ');
} else if ($pid_A > 0) {
// 父进程会得到子进程号,所以这里是父进程执行的逻辑
exit("A parent process exit \n");
}
// B 作为孤儿进程,被 init 进程托管,此时,进程 B 处于进程组 A 中
// 子进程得到的$pid为0, 所以以下是子进程执行的逻辑,受控制终端的影响,控制终端关闭则这里也会退出
// [子进程] 控制终端未关闭前,将当前子进程提升会会话组组长,及进程组的leader
// 进程 B 调用 posix_setsid 要求生成新的进程组,调用成功后当前进程组变为 B
if (-1 == posix_setsid()) {
exit("Failed to setsid\n");
}
// 此时进程 B 已经脱离任何的控制终端
// [子进程] 这时候在【进程组B】中,重新fork系统调用(二次fork)
$pid_B = pcntl_fork();
if ($pid_B < 0) {
exit('B fork error ');
} else if ($pid_B > 0) {
exit("B parent process exit \n");
}
// [新子进程] 这里是新生成的进程组,不受控制终端的影响,写写自己的业务逻辑代码
for ($i = 1; $i <= 100; $i++) {
sleep(1);
file_put_contents('daemon.log',$i . "--" . date("Y-m-d H:i:s", time()) . "\n",FILE_APPEND);
}
php runtime\daemon.php
PHP Fatal error: Uncaught Error: Call to undefined function pcntl_fork() in D:\phpStudy\PHPTutorial\WWW\notes\runtime\daemon.php:13
Stack trace:
#0 {main}
thrown in D:\phpStudy\PHPTutorial\WWW\notes\runtime\daemon.php on line 13
<span style="font-size: 16px;">php daemon.php</span><br/><span style="font-size: 16px;">...
97--2018-09-07 03:50:09
98--2018-09-07 03:50:10
99--2018-09-07 03:50:11
100--2018-09-07 03:50:12</span>
所以,现在即使关闭了终端,改脚本任然在后台守护进程运行
위 내용은 PHP7의 데몬 데몬 구현에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!