PHPによるデーモンプロセスの作り方(その1) 
2008/4/6 日曜日 15:57:02
マカーです。
2回に分けてPHPによるUNIXデーモンの作成方法について説明します。
PHPは他のLightweight Languageに比べてWeb開発言語という印象が強いですが、PHPでもデーモンを作ることもできます。
デーモンってなんだ?
メモリに常駐しバックグラウンドで様々なサービスを提供するプログラムです。
PHPで作ると何がうれしい?
C言語ではなくPHPで開発する事で、開発期間を短縮することが出来ます。
デーモンを開発する上で押さえるべきポイント
デーモンを開発する上で押さえるべきポイントは以下の通りです。
どんな言語を使う場合であっても共通です。
- セッションを現在のプロセスから独立させる。
デーモンはバックグラウンドで動作する為、制御端末から切り離します。
setsidにより行いますが、setsidは親プロセスで呼ぶと失敗するため、
forkで子プロセス生成し、子プロセスでsetsidを呼び出します。
再びforkして、親プロセスを終了することで、制御端末を持たなくなります。 - シグナルにより終了を行う。
プロセスを終了させる方法としてシグナルを使いますので、シグナルを処理できるようにします。
処理する必要のあるシグナルとしてSIGHUP、SIGTERM、SIGCHLDがあります。 - カレントディレクトリをルートディレクトリ”/”に変更する。
デーモンのカレントディレクトリである為に、管理者がファイルシステムをアンマウントできなくなるといった事態を防ぐ為に行います。
ルートディレクトリ以外にデーモンの処理に必要なファイルのあるディレクトリに移動する方法もあります。 - ファイルのアクセス権を確実に設定する為、umaskをクリアする。
ファイルのパーミッションを制御できるようにする為に行います。パーミッションはumaskの影響を受けますが、継承したumaskがどのようになっているのか分からないためです。
サンプルコード
以下、デーモンのスケルトンコードを示します。
#!/usr/bin/php
<?php
declare(ticks = 1);
define('MAX_SIG_QUEUE_LEN', 1024);
function sig_handler($signo = NULL)
{
static $s_signo = array();
if (is_null($signo))
return array_shift($s_signo);
$s_signo[] = $signo;
if ( count($s_signo) >= MAX_SIG_QUEUE_LEN )
array_shift($s_signo);
}
function daemonize()
{
if ( pcntl_fork() != 0 )
exit;
posix_setsid();
if ( pcntl_fork() != 0 )
exit;
chdir("/");
umask(0);
pcntl_signal(SIGTERM, "sig_handler");
pcntl_signal(SIGHUP, "sig_handler");
pcntl_signal(SIGCHLD, "sig_handler");
}
daemonize();
$living = TRUE;
while($living)
{
$signo = sig_handler();
switch ($signo)
{
case SIGTERM: // 終了シグナル
$living = FALSE; // 終了
break;
case SIGHUP: // HUPシグナル
// デーモン再起動処理
break;
case SIGCHLD: // 子プロセスが終了した場合
// 子プロセスのリソースの回収
pcntl_waitpid(-1, $status, WNOHANG);
break;
case NULL: // シグナルがない場合
sleep(1); // 適当な処理
break;
default:
}
}
今回は、こんな所で。
次回は一般のデーモンが行うその他の処理について補足したいと思います。