Linuxバックグラウンドサービスプロセスの開発


デーモンプロセス(Daemon)は、バックグラウンドで実行される特殊なプロセスです.制御端末とは独立して、あるタスクを周期的に実行したり、発生したイベントの処理を待ったりします.デーモンプロセスは有用なプロセスです.Linuxのほとんどのサーバは、デーモンプロセスで実装されています.例えば,インターネットサーバinetd,Webサーバhttpdなどである.同時に、デーモンプロセスは多くのシステムタスクを完了します.たとえば、ジョブプランニングプロセスcrond、印刷プロセスlpdなどです.
デーモンプロセスのプログラミング自体は複雑ではなく、複雑なのは各種バージョンのUnixの実現メカニズムが異なり、異なるUnix環境下でデーモンプロセスのプログラミング規則が一致しないことである.いくつかの本のルール(特にBSD 4.3と低バージョンのSystem V)をLinuxにコピーするとエラーが発生することに注意してください.Linuxのデーモン・プロセスのプログラミングの要点と詳細な例を次に示します.
一.デーモンプロセスとその特性
デーモンプロセスの最も重要な特性はバックグラウンドで実行されます.この点、DOSでの常駐メモリプログラムTSRはこれに似ている.次に、デーモンプロセスは、実行前の環境から分離する必要があります.これらの環境には、閉じていないファイル記述子、制御端末、セッションおよびプロセスグループ、作業ディレクトリ、およびファイル作成マスクなどが含まれます.これらの環境は、通常、保護プロセスが実行する親プロセス(特にshell)から継承されます.最後に、デーモンプロセスの起動方法には特別な点があります.Linuxシステムの起動時に起動スクリプト/etc/rcから起動できます.dで起動し、ジョブプランニングプロセスcrondで起動してもよいし、ユーザ端末(通常shell)で実行してもよい.
要するに,これらの特殊性を除いて,デーモンプロセスは通常のプロセスとほとんど変わらない.したがって,デーモンプロセスを記述することは,実際には1つの一般的なプロセスを上述したデーモンプロセスの特性に従ってデーモンプロセスに改造することである.プロセスをより深く認識すれば、理解とプログラミングが容易になります.
二.プロセスを守るプログラミングのポイント
前述したように,異なるUnix環境でのデーモンプロセスのプログラミング規則は一致していない.幸いなことに、プロセスを守るプログラミングの原則は実際には同じで、違いは具体的な実現の詳細が異なることです.この原則は,デーモンプロセスの特性を満たすことである.同時に、LinuxはSyetemVのSVR 4に基づいてPosix規格に準拠しており、BSD 4よりも便利に実現されている.プログラミングのポイントは以下の通りです.
1.バックグラウンドで実行します.
制御端末が停止しないようにDaemonをバックグラウンドに入れて実行します.方法は、プロセスでforkを呼び出して親プロセスを終了させ、Daemonをサブプロセスのバックグラウンドで実行させることです.
if(pid=fork())
exit(0); // , ,

2.制御端末を離脱し、セッションとプロセスグループにログインする
まずLinuxのプロセスと制御端末、ログインセッションとプロセスグループの関係を紹介する必要があります:プロセスは1つのプロセスグループに属して、プロセスグループ番号(GID)はプロセスグループ長のプロセス番号(PID)です.ログインセッションには、複数のプロセスグループを含めることができます.これらのプロセスグループは、制御端末を共有します.この制御端末は、通常、プロセスを作成するログイン端末である.制御端末、ログインセッションおよびプロセスグループは、通常、親プロセスから継承されます.私たちの目的はそれらから抜け出して、それらの影響を受けないようにすることです.方法は、第1点に基づいてsetsid()を呼び出してプロセスをセッショングループ長にすることです.
setsid();
説明:プロセスがセッショングループ長の場合setsid()呼び出しに失敗しました.しかし、最初のポイントは、プロセスがセッションリーダーではないことを保証しています.setsid()呼び出しに成功すると、プロセスは新しいセッショングループ長と新しいプロセスグループ長となり、元のログインセッションとプロセスグループから離れます.セッションプロセスの制御端末に対する独占性のため、プロセスは同時に制御端末から離脱する.
3.プロセスの制御端末の再開を禁止する
現在,プロセスは端末レスのセッションリーダーとなっている.しかし、制御端末を開くことを再申請することができます.プロセスがセッションリーダーにならないようにすることで、プロセスが制御端末を再開することを禁止できます.
if(pid=fork()) exit(0);//第1のサブプロセスを終了し、第2のサブプロセスを続行します(第2のサブプロセスはセッショングループ長ではありません).
4.開いているファイル記述子を閉じる
プロセスは、作成した親プロセスから開いているファイル記述子を継承します.シャットダウンしないと、システムリソースが浪費され、プロセスが存在するファイルシステムが取り外しられず、予期せぬエラーが発生します.次の方法で閉じます.
for(i=0;i開いているファイル記述子close(i);>
5.現在の作業ディレクトリの変更
プロセスがアクティブな場合、作業ディレクトリがあるファイルシステムは取り外すことができません.一般的には、作業ディレクトリをルートディレクトリに変更する必要があります.コアのダンプが必要な場合、実行ログを書き込むプロセスは、作業ディレクトリを/tmpchdir("/")などの特定のディレクトリに変更します.
6.リセットファイル作成マスク
プロセスは、作成した親プロセスからファイル作成マスクを継承します.デーモンプロセスによって作成されたファイルのアクセスビットを変更することができます.これを防止するために、ファイル作成マスククリア:umask(0);
7.SIGCHLD信号の処理
SIGCHLD信号の処理は必須ではない.しかし、一部のプロセス、特にサーバプロセスでは、リクエストが到来したときにサブプロセス処理リクエストが生成されることが多い.親プロセスがサブプロセスの終了を待たない場合、サブプロセスはゾンビプロセス(zombie)となり、システムリソースを占有します.親プロセスがサブプロセスの終了を待つと、親プロセスの負担が増加し、サーバプロセスの同時パフォーマンスに影響します.LinuxではSIGCHLD信号の動作を簡単にSIG_とすることができるIGN.
signal(SIGCHLD,SIG_IGN);
これにより、カーネルはサブプロセスの終了時にゾンビプロセスを生成しません.この点はBSD 4とは異なり、BSD 4の下でゾンビプロセスを解放するには、サブプロセスの終了を明示的に待たなければならない.
三.デーモンプロセスの例
デーモンプロセスの例は、メインプログラムtestの2つの部分を含む.cと初期化プログラムinit.c.メインプログラムは/tmpディレクトリのログtestに1分おきに.logは運転状態を報告する.初期化プログラムのinit_daemon関数は、デーモンプロセスの生成を担当します.読者はinitを利用できますdaemon関数は、独自のデーモンプロセスを生成します.
1. init.cリスト
#include < unistd.h >
#include < signal.h >
#include < sys/param.h >
#include < sys/types.h >
#include < sys/stat.h >

void init_daemon(void)
{
int pid;
int i;
if(pid=fork())
exit(0);// ,
else if(pid< 0)
exit(1);//fork ,
// ,
setsid();//
//
if(pid=fork())
exit(0);// ,
else if(pid< 0)
exit(1);//fork ,
// ,
//

for(i=0;i< NOFILE;++i)//
close(i);
chdir("/tmp");// /tmp
umask(0);//
return;
}

2. test.cリスト
#include < stdio.h >
#include < time.h >

void init_daemon(void);//

main()
{
FILE *fp;
time_t t;
init_daemon();// Daemon

while(1)// test.log
{
sleep(60);//
if((fp=fopen("test.log","a")) >=0)
{
t=time(0);
fprintf(fp,"Im here at %sn",asctime(localtime(&t)) );
fclose(fp);
}
}
}

以上のプログラムはRedHat Linux 6にある.0でコンパイルします.手順は次のとおりです.
コンパイル:gcc-g-o test init.c test.c
実行:./test
プロセスの表示:ps-ef
出力からtestデーモンプロセスの様々な特性が上記の要件を満たしていることがわかる.