Ein Daemon ist ein spezieller Prozess, der im Hintergrund l?uft und zur Ausführung bestimmter Systemaufgaben verwendet wird. Dieser Artikel führt Sie durch die Implementierung eines Daemons in PHP und stellt vor, worauf Sie bei der Programmierung achten müssen.
Der PHP-Implementierungsdaemon kann über die Erweiterungen pcntl
und posix
implementiert werden. pcntl
與 posix
擴(kuò)展實(shí)現(xiàn)。
編程中需要注意的地方有:
- 通過(guò)二次
pcntl_fork()
以及posix_setsid
讓主進(jìn)程脫離終端 - 通過(guò)
pcntl_signal()
忽略或者處理SIGHUP
信號(hào) - 多進(jìn)程程序需要通過(guò)二次
pcntl_fork()
或者pcntl_signal()
忽略SIGCHLD
信號(hào)防止子進(jìn)程變成 Zombie 進(jìn)程 - 通過(guò)
umask()
設(shè)定文件權(quán)限掩碼,防止繼承文件權(quán)限而來(lái)的權(quán)限影響功能 - 將運(yùn)行進(jìn)程的
STDIN/STDOUT/STDERR
重定向到/dev/null
或者其他流上
如果要做的更好,還需要注意:
- 如果通過(guò) root 啟動(dòng),運(yùn)行時(shí)更換到低權(quán)限用戶身份
- 及時(shí)
chdir()
防止操作錯(cuò)誤路徑 - 多進(jìn)程程序考慮定時(shí)重啟,防止內(nèi)存泄露
什么是daemon
文章的主角守護(hù)進(jìn)程(daemon),Wikipedia 上的定義是:
在一個(gè)多任務(wù)的電腦操作系統(tǒng)中,守護(hù)進(jìn)程(英語(yǔ):daemon,/?di?m?n/或/?de?m?n/)是一種在后臺(tái)執(zhí)行的電腦程序。此類程序會(huì)被以進(jìn)程的形式初始化。守護(hù)進(jìn)程程序的名稱通常以字母“d”結(jié)尾:例如,syslogd就是指管理系統(tǒng)日志的守護(hù)進(jìn)程。
通常,守護(hù)進(jìn)程沒(méi)有任何存在的父進(jìn)程(即PPID=1),且在UNIX系統(tǒng)進(jìn)程層級(jí)中直接位于init之下。守護(hù)進(jìn)程程序通常通過(guò)如下方法使自己成為守護(hù)進(jìn)程:對(duì)一個(gè)子進(jìn)程運(yùn)行fork,然后使其父進(jìn)程立即終止,使得這個(gè)子進(jìn)程能在init下運(yùn)行。這種方法通常被稱為“脫殼”。
UNIX環(huán)境高級(jí)編程(第二版)(以下使用簡(jiǎn)稱 APUE 指代) 13章有云:
守護(hù)進(jìn)程也成精靈進(jìn)程( daemon )是生存周期較長(zhǎng)的一種進(jìn)程。它們常常在系統(tǒng)自舉時(shí)啟動(dòng),僅在系統(tǒng)關(guān)閉時(shí)才終止。因?yàn)樗麄儧](méi)有控制終端,所以說(shuō)他們是在后臺(tái)運(yùn)行的。
這里注意到,daemon有如下特征:
- 沒(méi)有終端
- 后臺(tái)運(yùn)行
- 父進(jìn)程 pid 為1
想要查看運(yùn)行中的守護(hù)進(jìn)程可以通過(guò) ps -ax
或者 ps -ef
查看,其中 -x
表示會(huì)列出沒(méi)有控制終端的進(jìn)程。
實(shí)現(xiàn)關(guān)注點(diǎn)
二次 fork 與 setsid
fork 系統(tǒng)調(diào)用
fork 系統(tǒng)調(diào)用用于復(fù)制一個(gè)與父進(jìn)程幾乎完全相同的進(jìn)程,新生成的子進(jìn)程不同的地方在于與父進(jìn)程有著不同的 pid 以及有不同的內(nèi)存空間,根據(jù)代碼邏輯實(shí)現(xiàn),父子進(jìn)程可以完成一樣的工作,也可以不同。子進(jìn)程會(huì)從父進(jìn)程中繼承比如文件描述符一類的資源。
PHP 中的 pcntl
擴(kuò)展中實(shí)現(xiàn)了 pcntl_fork()
函數(shù),用于在 PHP 中 fork 新的進(jìn)程。
setsid 系統(tǒng)調(diào)用
setsid 系統(tǒng)調(diào)用則用于創(chuàng)建一個(gè)新的會(huì)話并設(shè)定進(jìn)程組 id。
這里有幾個(gè)概念:會(huì)話
,進(jìn)程組
。
在 Linux 中,用戶登錄產(chǎn)生一個(gè)會(huì)話(Session),一個(gè)會(huì)話中包含一個(gè)或者多個(gè)進(jìn)程組,一個(gè)進(jìn)程組又包含多個(gè)進(jìn)程。每個(gè)進(jìn)程組有一個(gè)組長(zhǎng)(Session Leader),它的 pid 就是進(jìn)程組的組 id。進(jìn)程組長(zhǎng)一旦打開(kāi)一個(gè)終端,這一個(gè)終端就被稱為控制終端。一旦控制終端發(fā)生異常(斷開(kāi)、硬件錯(cuò)誤等),會(huì)發(fā)出信號(hào)到進(jìn)程組組長(zhǎng)。
后臺(tái)運(yùn)行程序(如 shell 中以&
結(jié)尾執(zhí)行指令)在終端關(guān)閉之后也會(huì)被殺死,就是沒(méi)有處理好控制終端斷開(kāi)時(shí)發(fā)出的SIGHUP
信號(hào),而SIGHUP
- Verwenden Sie den zweiten
pcntl_fork()
undposix_setsid
, um den Hauptprozess aus dem Terminal zu holen - Ignorieren oder verarbeiten Sie das
SIGHUP
-Signal durchpcntl_signal()
- Mehrprozessprogramme müssen zweimal
pcntl_fork() oder pcntl_signal()
Ignorieren Sie das SignalSIGCHLD
, um zu verhindern, dass der untergeordnete Prozess zu einem Zombie-Prozess wird. - Legen Sie die Dateiberechtigungsmaske über
umask()
, um zu verhindern, dass sich von Dateiberechtigungen geerbte Berechtigungen auf Funktionen auswirken - Leiten Sie
STDIN/STDOUT/STDERR
des laufenden Prozesses nach/dev um /null
oder anderes Streaming
- Wenn Sie über Root beginnen, wechseln Sie zu einem Tief -privilegierte Benutzeridentit?t beim Ausführen von
- Rechtzeitiges
chdir()
Verhindern Sie Betriebsfehler - Erw?gen Sie, Multiprozessprogramme regelm??ig neu zu starten, um Speicherverluste zu verhindern ????
- Kein Terminal
- Im Hintergrund ausgeführt
- Die PID des übergeordneten Prozesses ist 1 ??Wenn Sie den laufenden Daemon-Prozess anzeigen m?chten, k?nnen Sie ihn über
- 控制終端斷開(kāi),SIGHUP 發(fā)送到進(jìn)程組組長(zhǎng)
- 進(jìn)程組組長(zhǎng)退出,SIGHUP 會(huì)發(fā)送到進(jìn)程組中的前臺(tái)進(jìn)程
- SIGHUP 常被用于通知進(jìn)程重載配置文件(APUE 中提及,daemon 由于沒(méi)有控制終端,被認(rèn)為不可能會(huì)收到這一個(gè)信號(hào),所以選擇復(fù)用)
- 父進(jìn)程處理
SIGCHLD
Die - daemon 不應(yīng)使用標(biāo)準(zhǔn)流
- 0/1/2 要設(shè)定成 /dev/null
Was ist ein Daemon
??Der Protagonist des Artikelsdaemon, Die Definition auf Wikipedia lautet: ????In einem In Multitasking-Computerbetriebssystemen ist ein Daemon (englisch: Daemon, /?di?m?n/ oder /?de?m?n/) ein Computerprogramm, das im Hintergrund ausgeführt wird. Solche Programme werden als Prozesse initialisiert. Die Namen von Daemon-Programmen enden normalerweise mit dem Buchstaben ?d“: syslogd bezieht sich beispielsweise auf den Daemon, der Systemprotokolle verwaltet.??Advanced Programming in UNIX Environment (Second Edition) (im Folgenden die Abkürzung wird verwendet, auf die sich APUE bezieht) In Kapitel 13 hei?t es: ??
Normalerweise verfügt der Daemon-Prozess über keinen vorhandenen übergeordneten Prozess (d. h. PPID=1) und befindet sich direkt unter init in der Prozesshierarchie des UNIX-Systems. Ein Daemon-Programm macht sich normalerweise selbst zu einem Daemon, indem es fork auf einem untergeordneten Prozess ausführt und dann seinen übergeordneten Prozess sofort beendet, damit der untergeordnete Prozess unter init ausgeführt werden kann. Diese Methode wird oft als ?Beschuss“ bezeichnet. ??
??Der Daemon-Prozess ist auch ein Daemon-Prozess (Daemon), also ein Prozess mit einem langen Lebenszyklus. Sie werden h?ufig beim Systemstart gestartet und erst beim Herunterfahren des Systems beendet. Da sie über kein Steuerungsterminal verfügen, sollen sie im Hintergrund laufen. ????Hier wird darauf hingewiesen, dass der Daemon die folgenden Eigenschaften aufweist: ??
ps -ax
oder ps -ef
anzeigen, wobei ist -x
bedeutet, dass es aufgelistet wird. Es gibt keinen Prozess, der das Terminal steuert. ??Umsetzungsbedenken
??Zweiter Fork und Setsid???? Fork-Systemaufruf????Fork Der Der Systemaufruf wird verwendet, um einen Prozess zu kopieren, der nahezu identisch mit dem übergeordneten Prozess ist. Der Unterschied zwischen dem neu generierten untergeordneten Prozess und dem übergeordneten Prozess besteht darin, dass er eine andere PID und einen anderen Speicherbereich hat und untergeordnete Prozesse k?nnen denselben Prozess ausführen. Der untergeordnete Prozess erbt Ressourcen wie Dateideskriptoren vom übergeordneten Prozess. ????Diepcntl
-Erweiterung in PHP implementiert die Funktion pcntl_fork()
, die zum Forken eines neuen Prozesses in PHP verwendet wird. ????setsid-Systemaufruf????setsid wird verwendet, um eine neue Sitzung zu erstellen und die Prozessgruppen-ID festzulegen. ????Hier gibt es mehrere Konzepte: Sitzung
, Prozessgruppe
. ????Unter Linux generiert die Benutzeranmeldung eine Sitzung. Eine Sitzung enth?lt eine oder mehrere Prozessgruppen und eine Prozessgruppe enth?lt mehrere Prozesse. Jede Prozessgruppe hat einen Sitzungsleiter und seine PID ist die Gruppen-ID der Prozessgruppe. Sobald der Prozessleiter ein Terminal ?ffnet, wird dieses Terminal als steuerndes Terminal bezeichnet. Sobald im Steuerterminal eine Ausnahme auftritt (Verbindungsunterbrechung, Hardwarefehler usw.), wird ein Signal an den Prozessgruppenleiter gesendet. ????Im Hintergrund laufende Programme (z. B. Ausführungsanweisungen in der Shell, die mit &
enden) werden auch nach dem Schlie?en des Terminals beendet, da der SIGHUP
ausgegeben wird, wenn die Verbindung zum Steuerterminal getrennt wird wird nicht ordnungsgem?? verarbeitet und das Standardverhalten des SIGHUP
-Signals für einen Prozess besteht darin, den Prozess zu beenden. ??Nach dem Aufruf des Systemaufrufs setsid
erstellt der aktuelle Prozess eine neue Prozessgruppe. Wenn das Terminal im aktuellen Prozess nicht ge?ffnet ist, gibt es in dieser Prozessgruppe kein Steuerterminal wird nein sein. Es liegt ein Problem damit vor, dass der Prozess durch Schlie?en des Terminals abgebrochen wird. setsid
系統(tǒng)調(diào)用之后,會(huì)讓當(dāng)前的進(jìn)程新建一個(gè)進(jìn)程組,如果在當(dāng)前進(jìn)程中不打開(kāi)終端的話,那么這一個(gè)進(jìn)程組就不會(huì)存在控制終端,也就不會(huì)出現(xiàn)因?yàn)殛P(guān)閉終端而殺死進(jìn)程的問(wèn)題。
PHP 中的 posix
擴(kuò)展中實(shí)現(xiàn)了 posix_setsid()
函數(shù),用于在 PHP 中設(shè)定新的進(jìn)程組。
孤兒進(jìn)程
父進(jìn)程比子進(jìn)程先退出,子進(jìn)程就會(huì)變成孤兒進(jìn)程。
init 進(jìn)程會(huì)收養(yǎng)孤兒進(jìn)程,即孤兒進(jìn)程的 ppid 變?yōu)?1。
二次 fork 的作用
首先,setsid
系統(tǒng)調(diào)用不能由進(jìn)程組組長(zhǎng)調(diào)用,會(huì)返回-1。
二次 fork 操作的樣例代碼如下:
$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"); }
假定我們?cè)诮K端中執(zhí)行應(yīng)用程序,進(jìn)程為 a,第一次 fork 會(huì)生成子進(jìn)程 b,如果 fork 成功,父進(jìn)程 a 退出。b 作為孤兒進(jìn)程,被 init 進(jìn)程托管。
此時(shí),進(jìn)程 b 處于進(jìn)程組 a 中,進(jìn)程 b 調(diào)用 posix_setsid
要求生成新的進(jìn)程組,調(diào)用成功后當(dāng)前進(jìn)程組變?yōu)?b。
此時(shí)進(jìn)程 b 事實(shí)上已經(jīng)脫離任何的控制終端,例程:
<?php 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); }
執(zhí)行程序之后:
? ~ php56 2fork1.php ? ~ ps ax | grep -v grep | grep -E 'process_|PID' PID TTY STAT TIME COMMAND 28203 ? Ss 0:00 process_b
從 ps 的結(jié)果來(lái)看,process_b 的 TTY 已經(jīng)變成了 ?
,即沒(méi)有對(duì)應(yīng)的控制終端。
代碼走到這里,似乎已經(jīng)完成了功能,關(guān)閉終端之后 process_b 也沒(méi)有被殺死,但是為什么還要進(jìn)行第二次 fork 操作呢?
StackOverflow 上的一個(gè)回答寫的很好:
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.
這是為了防止實(shí)際的工作的進(jìn)程主動(dòng)關(guān)聯(lián)或者意外關(guān)聯(lián)控制終端,再次 fork 之后生成的新進(jìn)程由于不是進(jìn)程組組長(zhǎng),是不能申請(qǐng)關(guān)聯(lián)控制終端的。
綜上,二次 fork 與 setsid 的作用是生成新的進(jìn)程組,防止工作進(jìn)程關(guān)聯(lián)控制終端。
SIGHUP 信號(hào)處理
一個(gè)進(jìn)程收到 SIGHUP
信號(hào)的默認(rèn)動(dòng)作是結(jié)束進(jìn)程。
而 SIGHUP
會(huì)在如下情況下發(fā)出:
由于實(shí)際的工作進(jìn)程不在前臺(tái)進(jìn)程組中,而且進(jìn)程組的組長(zhǎng)已經(jīng)退出并且沒(méi)有控制終端,不處理正常情況下當(dāng)然也沒(méi)有問(wèn)題,然而為了防止偶然的收到 SIGHUP
導(dǎo)致進(jìn)程退出,也為了遵循守護(hù)進(jìn)程程序設(shè)計(jì)的慣例,還是應(yīng)當(dāng)處理這一信號(hào)。
Zombie 進(jìn)程處理
何為 Zombie 進(jìn)程
簡(jiǎn)單來(lái)說(shuō),子進(jìn)程先于父進(jìn)程退出,父進(jìn)程沒(méi)有調(diào)用 wait
系統(tǒng)調(diào)用處理,進(jìn)程變?yōu)?Zombie 進(jìn)程。
子進(jìn)程先于父進(jìn)程退出時(shí),會(huì)向父進(jìn)程發(fā)送 SIGCHLD
信號(hào),如果父進(jìn)程沒(méi)有處理,子進(jìn)程也會(huì)變?yōu)?Zombie 進(jìn)程。
Zombie 進(jìn)程會(huì)占用可 fork 的進(jìn)程數(shù),Zombie 進(jìn)程過(guò)多會(huì)導(dǎo)致無(wú)法 fork 新的進(jìn)程。
此外,Linux 系統(tǒng)中 ppid 為 init 進(jìn)程的進(jìn)程,變?yōu)?Zombie 后會(huì)由 init 進(jìn)程回收管理。
Zombie 進(jìn)程的處理
從 Zombie 進(jìn)程的特點(diǎn),對(duì)于多進(jìn)程的daemon,可以通過(guò)兩個(gè)途徑解決這一問(wèn)題:
posix
-Erweiterung in PHP implementiert die Funktion posix_setsid()
, die zum Festlegen einer neuen Prozessgruppe in PHP verwendet wird. Wenn der übergeordnete Prozess vor dem untergeordneten Prozess beendet wird, wird der untergeordnete Prozess zu einem verwaisten Prozess.
Der Init-Prozess übernimmt den Waisenprozess, dh die PPID des Waisenprozesses wird 1. Die Rolle des sekund?ren Forks
Zuallererst kann der Systemaufruf setsid
nicht vom Prozessgruppenleiter aufgerufen werden und gibt -1 zurück.
Der Beispielcode für den zweiten Fork-Vorgang lautet wie folgt: ? ~ cat test_umask.php
<?php
chdir('/tmp');
umask(0066);
mkdir('test_umask', 0777);
? ~ php test_umask.php
? ~ ll /tmp | grep umask
drwx--x--x 2 root root 4.0K 8月 22 17:35 test_umask
Angenommen, wir führen die Anwendung im Terminal aus und der erste Fork generiert einen untergeordneten Prozess. b a geht aus. b Da es sich um einen verwaisten Prozess handelt, wird er vom Init-Prozess gehostet.
Zu diesem Zeitpunkt befindet sich Prozess b in Prozessgruppe a und Prozess b ruft posix_setsid
auf, um die Generierung einer neuen Prozessgruppe anzufordern. Nach erfolgreichem Aufruf wird die aktuelle Prozessgruppe zu b. Zu diesem Zeitpunkt hat Prozess b tats?chlich ein Kontrollterminal verlassen:
Nach der Ausführung des Programms:
? ~ 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??Aus den Ergebnissen von ps ist der TTY von Prozess_b zugeworden.
, das hei?t, es gibt kein entsprechendes Steuerterminal. ????Der Code scheint zu diesem Zeitpunkt seine Funktion abgeschlossen zu haben. Prozess_b wurde nach dem Schlie?en des Terminals nicht beendet, aber warum gibt es einen zweiten Fork-Vorgang? ????Eine Antwort??gut geschrieben auf StackOverflow:?????? Der zweite Fork (2) soll sicherstellen, dass der neue Prozess kein Sitzungsleiter ist, sodass er nicht (versehentlich) ein steuerndes Terminal zuweisen kann, da D?monen niemals ein steuerndes Terminal haben sollten.???? ??Das ist um zu verhindern, dass der tats?chliche Arbeitsprozess aktiv oder versehentlich eine Verbindung mit dem Steuerterminal herstellt. Der nach dem erneuten Verzweigen generierte neue Prozess kann keine Zuordnung zum Steuerterminal beantragen, da er nicht der Anführer der Prozessgruppe ist. ????Zusammenfassend besteht die Funktion von Secondary Fork und Setsid darin, eine neue Prozessgruppe zu generieren und zu verhindern, dass der Arbeitsprozess mit dem Steuerterminal verknüpft wird. ????????SIGHUP-Signalverarbeitung????????Die Standardaktion eines Prozesses, der dasSIGHUP
-Signal empf?ngt, besteht darin, den Prozess zu beenden. ????UndSIGHUP
wird unter den folgenden Umst?nden ausgegeben: ????Das Steuerterminal ist nicht angeschlossen, SIGHUP wird an den Prozessgruppenleiter gesendet. ????Der Prozessgruppenleiter verl?sst das System, SIGHUP wird gesendet zur Prozessgruppe Der Vordergrundprozess ????SIGHUP wird oft verwendet, um den Prozess zum Neuladen der Konfigurationsdatei zu benachrichtigen (in APUE erw?hnt, da der Daemon kein Steuerterminal hat, wird es als unm?glich angesehen, dieses Signal zu empfangen, also entscheidet er sich dafür (Wiederverwendung) ??????Aufgrund der tats?chlichen Der Arbeitsprozess befindet sich nicht in der Vordergrundprozessgruppe und der Leiter der Prozessgruppe hat das Terminal verlassen. Unter normalen Umst?nden gibt es jedoch kein Problem Um zu verhindern, dass der Prozess versehentlich
SIGHUP
empf?ngt und den Prozess beendet, sollte dieses Signal weiterhin verarbeitet werden, um den Konventionen der Daemon-Programmierung zu folgen. ????????Zombie-Prozessverarbeitung??????????Was ist ein Zombie-Prozess???????Einfach ausgedrückt: Der untergeordnete Prozess wird vor dem übergeordneten Prozess beendet. Der übergeordnete Prozess ruft nicht die Systemaufrufverarbeitungwait
auf , und der Prozess wird zum Zombie-Prozess. ????Wenn der untergeordnete Prozess vor dem übergeordneten Prozess beendet wird, sendet er das SignalSIGCHLD
an den übergeordneten Prozess. Wenn der übergeordnete Prozess dies nicht verarbeitet, wird auch der untergeordnete Prozess zu einem Zombie-Prozess. ????Zombie-Prozesse belegen die Anzahl der Prozesse, die gegabelt werden k?nnen. Zu viele Zombie-Prozesse führen dazu, dass keine neuen Prozesse gegabelt werden k?nnen. ????Darüber hinaus wird im Linux-System ein Prozess, dessen ppid der Init-Prozess ist, vom Init-Prozess recycelt und verwaltet, nachdem er zu einem Zombie geworden ist. ??????Zombie-Prozessverarbeitung??????Aufgrund der Eigenschaften des Zombie-Prozesses kann dieses Problem für Multiprozess-Daemons auf zwei Arten gel?st werden: ????Der übergeordnete Prozess verarbeitet den
SIGCHLD
signal?? ??Lassen Sie den untergeordneten Prozess von init übernehmen??????Sie müssen nicht mehr über die Verarbeitung von Signalen durch den übergeordneten Prozess sagen. Registrieren Sie einfach die Rückruffunktion für die Signalverarbeitung und rufen Sie die Recycling-Methode auf. ????Damit der untergeordnete Prozess von init übernommen wird, k?nnen Sie die Methode von fork zweimal verwenden, sodass der untergeordnete Prozess a aus der ersten Abzweigung dann den eigentlichen Arbeitsprozess b abzweigen und a zuerst verlassen kann, wodurch b entsteht ein verwaister Prozess. Auf diese Weise kann er vom Init-Prozess gehostet werden. ????????umask????????umask wird vom übergeordneten Prozess geerbt und wirkt sich auf die Berechtigungen der erstellten Dateien aus. ????PHP ??Manual?? erw?hnt: ??????umask() setzt PHPs umask auf mask & 0777 und gibt die ursprüngliche umask zurück. Bei Verwendung von PHP als Servermodul wird die umask nach jeder Anfrage wiederhergestellt. ??????Wenn die umask des übergeordneten Prozesses nicht richtig eingestellt ist, treten bei der Ausführung einiger Dateivorg?nge unerwartete Effekte auf: ??? ~ cat test_umask.php <?php chdir('/tmp'); umask(0066); mkdir('test_umask', 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è)樣例:
上述代碼幾乎完成了文章最開(kāi)始部分提及的各個(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)程打開(kāi)
/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ì)在該終端上見(jiàn)到守護(hù)進(jìn)程的輸出,用戶也不可期望他們?cè)诮K端上的輸入會(huì)由守護(hù)進(jìn)程讀取。簡(jiǎn)單來(lái)說(shuō):
例程中使用:
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)閉所有可以打開(kāi)的文件描述符,包括標(biāo)準(zhǔn)輸入輸出錯(cuò)誤; 打開(kāi)/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ù)制代碼開(kāi)源項(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('can not open stdoutFile ' . 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)槿肿兞浚WC引用的存在。
推薦學(xué)習(xí):《PHP視頻教程》
Das obige ist der detaillierte Inhalt vonWas ist ein D?mon? Wie implementiert man einen Daemon in PHP?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Hei?e KI -Werkzeuge

Undress AI Tool
Ausziehbilder kostenlos

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Clothoff.io
KI-Kleiderentferner

Video Face Swap
Tauschen Sie Gesichter in jedem Video mühelos mit unserem v?llig kostenlosen KI-Gesichtstausch-Tool aus!

Hei?er Artikel

Hei?e Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Benutzerspracheingabe wird erfasst und über die Mediarecorder-API des Front-End-JavaScript an das PHP-Backend gesendet. 2. PHP speichert das Audio als tempor?re Datei und ruft STTAPI (z. B. Google oder Baidu Voiceerkennung) auf, um sie in Text umzuwandeln. 3. PHP sendet den Text an einen KI -Dienst (wie OpenAigpt), um intelligente Antwort zu erhalten. 4. PHP ruft dann TTSAPI (wie Baidu oder Google Voice -Synthese) auf, um die Antwort in eine Sprachdatei umzuwandeln. 5. PHP streams die Sprachdatei zurück zum Spielen, um die Interaktion abzuschlie?en. Der gesamte Prozess wird von PHP dominiert, um eine nahtlose Verbindung zwischen allen Links zu gew?hrleisten.

Die Kernmethode zum Aufbau sozialer Freigabefunktionen in PHP besteht darin, dynamisch Freigabelinks zu generieren, die den Anforderungen jeder Plattform entsprechen. 1. Erhalten Sie zuerst die aktuelle Seite oder die angegebenen URL- und Artikelinformationen. 2. Verwenden Sie Urlencode, um die Parameter zu codieren. 3.. Splei? und generieren Teilenverbindungen gem?? den Protokollen jeder Plattform; 4. Zeigen Sie Links im vorderen Ende an, damit Benutzer klicken und freigeben k?nnen. 5. generieren Sie Dynamik OG -Tags auf der Seite, um die Anzeige der Freigabe inhaltlich zu optimieren. 6. Achten Sie darauf, dass Sie den Benutzereingaben entkommen, um XSS -Angriffe zu verhindern. Diese Methode erfordert keine komplexe Authentifizierung, weist nur geringe Wartungskosten auf und eignet sich für die meisten Anforderungen an den Inhaltsaustausch.

Um die Textfehlerkorrektur und die Syntaxoptimierung mit AI zu realisieren, müssen Sie die folgenden Schritte ausführen: 1. W?hlen Sie ein geeignetes AI -Modell oder ein geeignetes AI -Modell oder ein geeignetes AI -Modell wie Baidu, Tencent API oder Open Source NLP -Bibliothek aus; 2. Rufen Sie die API über die Curl oder das Guzzle von PHP auf und verarbeiten Sie die Rückgabeergebnisse. 3.. Informationen zur Fehlerkorrektur in der Anwendung anzeigen und erm?glichen den Benutzern, zu w?hlen, ob sie angenommen werden sollen. 4. Verwenden Sie PHP-L und PHP_CODESNIFFER für die Syntaxerkennung und -codeoptimierung. 5. sammeln Sie kontinuierlich Feedback und aktualisieren Sie das Modell oder die Regeln, um den Effekt zu verbessern. Konzentrieren Sie sich bei der Auswahl von AIAPI auf die Bewertung von Genauigkeit, Reaktionsgeschwindigkeit, Preis und Unterstützung für PHP. Die Codeoptimierung sollte den PSR -Spezifikationen folgen, Cache vernünftigerweise verwenden, zirkul?re Abfragen vermeiden, den Code regelm??ig überprüfen und x verwenden

1. Maximierung des kommerziellen Wertes des Kommentarsystems erfordert die Kombination der pr?zisen Lieferung native Werbung, benutzerbezahlte Wertsch?pfungsdienste (z. B. Bilder hochladen, Aufladungskommentare), den Incentive-Mechanismus basierend auf der Qualit?t der Kommentare und der Anonymen Daten Insight-Monetarisierung von Compliance; 2. Die Prüfungsstrategie sollte eine Kombination aus dynamischer Keyword-Filterung und Benutzerkennungsmechanismen vorab der Auditing einsetzen, die durch die Qualit?t der Kommentarqualit?t erg?nzt werden, um die hierarchische Inhaltsbelastung zu erreichen. 3. Die Anti-Pushing erfordert die Konstruktion einer mehrschichtigen Verteidigung: Recaptchav3 sensorlose überprüfung, Honeypot-Honeypot-Feldkennungroboter, IP und Zeitstempelfrequenzgrenze verhindert die Bew?sserung, und die Erkennung von Inhalten markiert verd?chtige Kommentare und st?ndig mit Angriffen.

PHP führt nicht direkt die KI-Image-Verarbeitung durch, sondern integriert sich über APIs, da es in der Webentwicklung und nicht in Bezug auf Computerintensive Aufgaben gut ist. Die API -Integration kann die professionelle Arbeitsteilung erreichen, die Kosten senken und die Effizienz verbessern. 2. Integration von Schlüsseltechnologien umfasst die Verwendung von Guzzle oder Curl zum Senden von HTTP-Anforderungen, JSON-Datencodierung und -decodierung, API-Schlüsselsicherheitsauthentifizierung, asynchroner Warteschlangenverarbeitungsaufgaben, robuster Fehlerbehebung und Wiederholungsmechanismus, Bildspeicherung und Anzeige. 3. Die gemeinsamen Herausforderungen sind API -Kosten au?er Kontrolle, unkontrollierbare Erzeugungsergebnisse, schlechte Benutzererfahrung, Sicherheitsrisiken und schwieriges Datenmanagement. In den Antwortstrategien werden Benutzerquoten und -darstellungen festgelegt, die Auswahl von ProPT-Anleitungen und mehrfizierende Auswahl, asynchrone Benachrichtigungen und Fortschrittsaufforderungen, wichtige Speicher- und Inhaltsprüfungen sowie Cloud-Speicher vorhanden.

PHP sorgt für die Inventarabzugsatomizit?t durch Datenbanktransaktionen und Forupdate -Reihenschl?sser, um eine hohe gleichzeitige überverl?ssigkeit zu verhindern. 2. Multi-Plattform-Inventarkonsistenz h?ngt von zentraler Verwaltung und ereignisgesteuerter Synchronisation ab, die API/Webhook-Benachrichtigungen und Nachrichtenwarteschlangen kombiniert, um eine zuverl?ssige Datenübertragung sicherzustellen. 3. Der Alarmmechanismus sollte in verschiedenen Szenarien niedrige Lagerbest?nde, Null/Negativ -Inventar, unerwünschte Verkaufszyklen, Nachschubzyklen und abnormale Schwankungsstrategien festlegen und die Auswahl von Dingtalk, SMS oder E -Mail -Verantwortlichen gem?? der Dringlichkeit ausw?hlen, und die Alarminformationen müssen vollst?ndig und frei sein, um die Anpassung und die Vergewaltigungsreaktion zu erreichen.

PhpisstillrelevantinMoDernEnterpriseEnvironments.1.ModerPhp (7.xand8.x) Angebote, strenge, jitkompilation und moderne Syntax, machte ma?geschneiderte Foreiglableforlarge-ScaleApplikationen

Die Kernrolle von Homebrew bei der Konstruktion der Mac -Umgebung besteht darin, die Installation und Verwaltung der Software zu vereinfachen. 1. Homebrew verarbeitet automatisch Abh?ngigkeiten und verkapselt komplexe Kompilierungs- und Installationsprozesse in einfache Befehle. 2. Bietet ein einheitliches Softwarepaket -?kosystem, um die Standardisierung des Software -Installationsorts und der Konfiguration zu gew?hrleisten. 3. Integriert Service -Management -Funktionen und kann Dienste leicht über Brewservices starten und stoppen. 4. Bequemes Software -Upgrade und -wartung und verbessert die Sicherheit und Funktionalit?t der Systeme.
