TL;DR
PHP 実装デーモンは、pcntl
および posix
拡張機能を通じて実装できます。
プログラミングで注意する必要があることは次のとおりです。
- メイン プロセスが 2 番目の
pcntl_fork()
およびposix_setsid# を介してターミナルから離れるようにします。
Pass - pcntl_signal()
シグナルを無視または処理します
マルチプロセス プログラムは 2 回渡す必要があります - pcntl_fork()
または
pcntl_signal()シグナルを無視して、子プロセスがゾンビ プロセスになるのを防ぎます
- umask()## を通じてファイル許可マスクを設定します# ファイル権限の継承を防ぐため、結果として生じる権限影響関数
は、実行中のプロセスの
STDIN/STDOUT/STDERR - を
/dev/null
または他のストリームにリダイレクトします より良い結果を出したい場合は、次の点にも注意する必要があります。
#root から開始する場合は、実行時に低い特権のユーザー ID に変更してください
- Timely
- chdir() 操作エラー パスの防止
メモリ リークを防ぐためにマルチプロセス プログラムを定期的に再起動することを検討してください
- デーモンとは
マルチタスクのコンピューター オペレーティング システムでは、デーモン (英語: daemon、/ˈdiːmən/ または /ˈdeɪmən/) は次のとおりです。バックグラウンドで実行されるコンピューター プログラム。このようなプログラムはプロセスとして初期化されます。デーモン プログラムの名前は通常、文字「d」で終わります。たとえば、syslogd はシステム ログを管理するデーモンを指します。
通常、デーモン プロセスには既存の親プロセス (つまり、PPID=1) がなく、UNIX システム プロセス階層の init の直下にあります。デーモン プログラムは通常、子プロセスで fork を実行し、その後親プロセスを直ちに終了して、子プロセスが init で実行できるようにすることで、自分自身をデーモンにします。この方法は、「シェル処理」と呼ばれることがよくあります。
UNIX 環境での高度なプログラミング (第 2 版) (以下、APUE と呼びます) 第 13 章にクラウドがあります:
デーモン プロセスはエルフ プロセスにもなります(デーモン) はライフサイクルの長いプロセスです。多くの場合、これらはシステムの起動時に開始され、システムがシャットダウンされたときにのみ終了します。制御端末がないため、バックグラウンドで実行されると言われています。
ここで、デーモンには次の特徴があることに注意してください:
ターミナルなし
- バックグラウンドで実行
- 親プロセスpid は 1
- 実行中のデーモン プロセスを表示したい場合は、 ps -ax
ps -ef を使用して表示できます。ここで
-x はリストに表示されることを意味します 端末を制御するプロセスはありません。
実装に関する懸念事項
pcntl
拡張機能は、PHP で新しいプロセスをフォークするために使用されるpcntl_fork() 関数を実装します。
setsid システム コール
セッション
、プロセス グループといういくつかの概念があります。
Linux では、ユーザーのログインによりセッションが生成されます。セッションには 1 つ以上のプロセス グループが含まれ、プロセス グループには複数のプロセスが含まれます。各プロセス グループにはセッション リーダーがあり、その pid はプロセス グループのグループ ID です。プロセス リーダーがターミナルを開くと、このターミナルは制御ターミナルと呼ばれます。制御端末で例外(切断、ハードウェアエラーなど)が発生すると、プロセスグループリーダーに信号が送信されます。
&
で終わるシェル実行命令など) も、端末が閉じられた後、つまり制御端末が切断されたときに発行されたSIGHUP 後に強制終了されます。 シグナルは適切に処理されず、プロセスの
SIGHUP シグナルのデフォルトの動作はプロセスを終了します。
Call
setsid
PHP の
posix
posix_setsid() 関数を実装します。
孤立プロセス
2 番目のフォークの役割
まず、setsid
システム コールはプロセス グループ リーダーから呼び出すことができず、-1 を返します。
2 番目のフォーク操作のサンプル コードは次のとおりです。
$pid1 = pcntl_fork(); if ($pid1 > 0) { exit(0); } else if ($pid1 0) { exit(0); } else if ($pid2 <p> </p><p> ターミナルでアプリケーションを実行すると仮定します。プロセスは a で、最初のフォークは子プロセス b が生成されます。フォークが成功すると、親プロセス a が終了します。 b 孤立プロセスとして、init プロセスによってホストされます。 </p><p>現時点では、プロセス b はプロセス グループ a に属しており、プロセス b は <code>posix_setsid</code> を呼び出して新しいプロセス グループの生成を要求します。呼び出しが成功すると、現在のプロセス グループは次のようになります。 b. </p><p>この時点で、プロセス b は実際には制御端末から切り離されています。ルーチン: </p><pre class="brush:php;toolbar:false"><?php cli_set_process_title('process_a'); $pidA = pcntl_fork(); if ($pidA > 0) { exit(0); } else if ($pidA <p> </p><p>プログラム実行後: </p><pre class="brush:php;toolbar:false">➜ ~ php56 2fork1.php ➜ ~ ps ax | grep -v grep | grep -E 'process_|PID' PID TTY STAT TIME COMMAND 28203 ? Ss 0:00 process_b
ps の結果からすると、process_b の TTY は になりましたか?
、つまり、対応する制御端子が存在しません。
コードがこの時点に到達すると、関数が完了したように見えます。ターミナルを閉じた後でも process_b は強制終了されていませんが、なぜ 2 回目の fork 操作があるのでしょうか?
StackOverflow の回答はよく書かれています:
2 番目の fork(2) は、新しいプロセスがセッション リーダーではないことを確認するためにあります。デーモンは制御端末を持つことは想定されていないため、(偶然に) 制御端末を割り当てます。
これは、実際の作業プロセスが制御端末に積極的に関連付けられたり、誤って関連付けられたりすることを防ぐためです。フォーク後に生成された新しいプロセスは、プロセス グループのリーダーではないため、関連付けられた制御端末に適用できません。
要約すると、セカンダリ フォークと setid の機能は、新しいプロセス グループを生成し、作業プロセスが制御端末に関連付けられるのを防ぐことです。
SIGHUP シグナルの処理
SIGHUP
シグナルを受信したプロセスのデフォルトのアクションは、プロセスを終了することです。
そして SIGHUP
は次の状況で発行されます。
- 制御端末が切断され、SIGHUP がプロセス グループ リーダーに送信されます
- プロセス グループ グループ リーダーが終了すると、プロセス グループのフォアグラウンド プロセスに SIGHUP が送信されます。
- SIGHUP は、プロセスに設定ファイルをリロードするように通知するためによく使用されます (APUE で述べたように、デーモンは考慮されます)制御端子がないため受信する可能性は低い) これは信号であるため、再利用することにします)
実際に作業しているプロセスはフォアグラウンド プロセス グループに含まれておらず、リーダーがプロセスグループのプロセスが終了しており、端末を制御していないため、通常であれば当然処理は行われませんが、問題は、SIGHUP
の誤受信によるプロセスの終了を防ぐため、デーモン プログラミングの規則に従うためには、このシグナルも処理する必要があります。
ゾンビ プロセスの処理
ゾンビ プロセスとは
簡単に言うと、子プロセスは親プロセスよりも先に終了し、親プロセスは wait を呼び出しません。
システムコールが処理され、プロセスはゾンビプロセスになります。
子プロセスが親プロセスより先に終了すると、SIGCHLD
シグナルが親プロセスに送信されます。親プロセスが処理しない場合、子プロセスもゾンビになります。プロセス。
ゾンビ プロセスは、フォークできるプロセスの数を占有します。ゾンビ プロセスが多すぎると、新しいプロセスをフォークできなくなります。
また、Linux システムでは、ppid が init プロセスであるプロセスは、Zombie になった後、init プロセスによって再利用され、管理されます。
ゾンビ プロセスの処理
ゾンビ プロセスの特性から、マルチプロセス デーモンの場合、この問題は 2 つの方法で解決できます。
- 親プロセスの処理
SIGCHLD
Signal - 子プロセスを init に引き継がせる
親プロセスの信号処理について詳しく説明する必要はありません。信号処理を登録するだけです。コールバック関数を呼び出して、リサイクルメソッドを呼び出します。
子プロセスを init によって引き継ぐには、fork メソッドを 2 回使用できます。これにより、最初の fork からの子プロセス a が実際に作業しているプロセス b をフォークアウトし、a を終了させることができます。まず、b が孤立プロセスになり、init プロセスでホストできるようにします。
umask
umask は親プロセスから継承され、ファイルを作成する権限に影響します。
PHP マニュアルには次のように記載されています:
umask() は PHP の umask をマスク & 0777 に設定し、元の umask を返します。 PHP がサーバー モジュールとして使用されている場合、umask はリクエストのたびに復元されます。
親プロセスの umask が適切に設定されていない場合、一部のファイル操作を実行するときに予期しない影響が発生します。
➜ ~ 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
したがって、毎回、期待される権限に従ってファイルを操作できるようにするには、umask 値を 0 に設定する必要があります。
リダイレクト 0/1/2
ここでの 0/1/2 は、それぞれ STDIN/STDOUT/STDERR
、つまり標準入力/出力/エラー 3 を指します。流れ。
サンプル
まずサンプルを見てみましょう:
<?php // not_redirect_std_stream_daemon.php $pid1 = pcntl_fork(); if ($pid1 > 0) { exit(0); } else if ($pid1 0) { exit(0); } else if ($pid2 <p> </p><p>上記のコードは、記事の冒頭で述べたすべての側面をほぼ完成させています。唯一の違いは、標準ストリームが処理されないことです。このプログラムは、<code>php not_redirect_std_stream_daemon.php</code> ディレクティブを使用してバックグラウンドで実行することもできます。 </p><p>在 <code>sleep</code> 的间隙,关闭终端,会发现进程退出。</p><p>通过 <code>strace</code> 观察系统调用的情况:</p><pre class="brush:php;toolbar:false">➜ ~ strace -p 6723 Process 6723 attached - interrupt to quit restart_syscall(<...>) = 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</...>
发现发生了 EIO 错误,导致进程退出。
原因很简单,即我们编写的 daemon 程序使用了当时启动时终端提供的标准流,当终端关闭时,标准流变得不可读不可写,一旦尝试读写,会导致进程退出。
在信海龙的博文《一个echo引起的进程崩溃》中也提到过类似的问题。
解决方案
APUE 样例
APUE 13.3中提到过一条编程规则(第6条):
某些守护进程打开
/dev/null
时期具有文件描述符0、1和2,这样,任何一个视图读标准输入、写标准输出或者标准错误的库例程都不会产生任何效果。因为守护进程并不与终端设备相关联,所以不能在终端设备上显示器输出,也无从从交互式用户那里接受输入。及时守护进程是从交互式会话启动的,但因为守护进程是在后台运行的,所以登录会话的终止并不影响守护进程。如果其他用户在同一终端设备上登录,我们也不会在该终端上见到守护进程的输出,用户也不可期望他们在终端上的输入会由守护进程读取。
简单来说:
- daemon 不应使用标准流
- 0/1/2 要设定成 /dev/null
例程中使用:
for (i = 0; i <p> </p><p>实现了这一个功能。<code>dup()</code> (参考手册)系统调用会复制输入参数中的文件描述符,并复制到最小的未分配文件描述符上。所以上述例程可以理解为:</p><pre class="brush:php;toolbar:false">关闭所有可以打开的文件描述符,包括标准输入输出错误; 打开/dev/null并赋值给变量fd0,因为标准输入已经关闭了,所以/dev/null会绑定到0,即标准输入; 因为最小未分配文件描述符为1,复制文件描述符0到文件描述符1,即标准输出也绑定到/dev/null; 因为最小未分配文件描述符为2,复制文件描述符0到文件描述符2,即标准错误也绑定到/dev/null;
开源项目实现:Workerman
Workerman 中的 Worker.php 中的 resetStd()
方法实现了类似的操作。
/** * 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 中如此实现,结合博文,可能与 PHP 的 GC 机制有关,对于 fd 0 1 2来说,PHP 会维持对这三个资源的引用计数,在直接 fclose 之后,会使得这几个 fd 对应的资源类型的变量引用计数为0,导致触发回收。所需要做的就是将这些变量变为全局变量,保证引用的存在。
推荐教程:《php教程》
以上がPHP はデーモンを実装します - バックエンドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

php把负数转为正整数的方法:1、使用abs()函数将负数转为正数,使用intval()函数对正数取整,转为正整数,语法“intval(abs($number))”;2、利用“~”位运算符将负数取反加一,语法“~$number + 1”。

实现方法:1、使用“sleep(延迟秒数)”语句,可延迟执行函数若干秒;2、使用“time_nanosleep(延迟秒数,延迟纳秒数)”语句,可延迟执行函数若干秒和纳秒;3、使用“time_sleep_until(time()+7)”语句。

php除以100保留两位小数的方法:1、利用“/”运算符进行除法运算,语法“数值 / 100”;2、使用“number_format(除法结果, 2)”或“sprintf("%.2f",除法结果)”语句进行四舍五入的处理值,并保留两位小数。

判断方法:1、使用“strtotime("年-月-日")”语句将给定的年月日转换为时间戳格式;2、用“date("z",时间戳)+1”语句计算指定时间戳是一年的第几天。date()返回的天数是从0开始计算的,因此真实天数需要在此基础上加1。

php判断有没有小数点的方法:1、使用“strpos(数字字符串,'.')”语法,如果返回小数点在字符串中第一次出现的位置,则有小数点;2、使用“strrpos(数字字符串,'.')”语句,如果返回小数点在字符串中最后一次出现的位置,则有。

方法:1、用“str_replace(" ","其他字符",$str)”语句,可将nbsp符替换为其他字符;2、用“preg_replace("/(\s|\ \;||\xc2\xa0)/","其他字符",$str)”语句。

php字符串有下标。在PHP中,下标不仅可以应用于数组和对象,还可应用于字符串,利用字符串的下标和中括号“[]”可以访问指定索引位置的字符,并对该字符进行读写,语法“字符串名[下标值]”;字符串的下标值(索引值)只能是整数类型,起始值为0。

查找方法:1、用strpos(),语法“strpos("字符串值","查找子串")+1”;2、用stripos(),语法“strpos("字符串值","查找子串")+1”。因为字符串是从0开始计数的,因此两个函数获取的位置需要进行加1处理。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

Safe Exam Browser
Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。

DVWA
Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、

SublimeText3 英語版
推奨: Win バージョン、コードプロンプトをサポート!

EditPlus 中国語クラック版
サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません

SublimeText3 Linux 新バージョン
SublimeText3 Linux 最新バージョン
