UNP学習ノート(第13章デーモンプロセスとinetdスーパーサーバ)

19560 ワード

デーモンプロセスについてapueのノートを表示できますhttp://www.cnblogs.com/runnyu/p/4645046.html
 
 
daemon_init関数
次はdaemonという名前でInit関数は、通常サーバプログラムから呼び出すことで、通常のプロセスをデーモンプロセスに変更できます.

 1 #include    "unp.h"
 2 #include    
 3 
 4 #define    MAXFD    64
 5 
 6 extern int    daemon_proc;    /* defined in error.c */
 7 
 8 int
 9 daemon_init(const char *pname, int facility)
10 {
11     int        i;
12     pid_t    pid;
13 
14     if ( (pid = Fork()) < 0)
15         return (-1);
16     else if (pid)
17         _exit(0);            /* parent terminates */
18 
19     /* child 1 continues... */
20 
21     if (setsid() < 0)            /* become session leader */
22         return (-1);
23 
24     Signal(SIGHUP, SIG_IGN);
25     if ( (pid = Fork()) < 0)
26         return (-1);
27     else if (pid)
28         _exit(0);            /* child 1 terminates */
29 
30     /* child 2 continues... */
31 
32     daemon_proc = 1;            /* for err_XXX() functions */
33 
34     chdir("/");                /* change working directory */
35 
36     /* close off file descriptors */
37     for (i = 0; i < MAXFD; i++)
38         close(i);
39 
40     /* redirect stdin, stdout, and stderr to /dev/null */
41     open("/dev/null", O_RDONLY);
42     open("/dev/null", O_RDWR);
43     open("/dev/null", O_RDWR);
44 
45     openlog(pname, LOG_PID, facility);
46 
47     return (0);                /* success */
48 }

View Code
デーモンとして実行される時間取得サーバプログラム

 1 #include    "unp.h"
 2 #include    
 3 
 4 int
 5 main(int argc, char **argv)
 6 {
 7     int listenfd, connfd;
 8     socklen_t addrlen, len;
 9     struct sockaddr    *cliaddr;
10     char buff[MAXLINE];
11     time_t ticks;
12 
13     if (argc < 2 || argc > 3)
14         err_quit("usage: daytimetcpsrv2 [  ] ");
15 
16     daemon_init(argv[0], 0);
17 
18     if (argc == 2)
19         listenfd = Tcp_listen(NULL, argv[1], &addrlen);
20     else
21         listenfd = Tcp_listen(argv[1], argv[2], &addrlen);
22 
23     cliaddr = Malloc(addrlen);
24 
25     for ( ; ; ) {
26         len = addrlen;
27         connfd = Accept(listenfd, cliaddr, &len);
28         err_msg("connection from %s", Sock_ntop(cliaddr, len));
29 
30         ticks = time(NULL);
31         snprintf(buff, sizeof(buff), "%.24s\r
", ctime(&ticks)); 32 Write(connfd, buff, strlen(buff)); 33 34 Close(connfd); 35 } 36 }

View Code
 
 
 
inetdデーモン
典型的なUNIXシステムには、FTP、Telnet、Rlogin、TFTPなどのクライアント要求の到着を待つだけの多くのサーバが存在する可能性がある.
以前は、これらのサービスはすべて1つのプロセスに関連付けられており、各プロセスはほぼ同じ起動タスクを実行していました.このモデルには、次の2つの問題があります.
1.これらのデーモンプロセスには、ほとんど同じ起動コードが含まれています.
2.各デーモン・プロセスは、プロセス・テーブル内でテーブル・アイテムを占有し、ほとんどの時間をスリープ状態にします.
4.3 BSDバージョンのTCPまたはUDPベースのサーバは、inetdデーモンプロセスを使用して上記の2つの問題を解決できます.
1.通常のデーモンプロセスのほとんどの起動詳細をinetdで処理することによって、デーモンプロセスの作成を簡略化する.
2.単一プロセス(inetd)は、各サービスのプロセスの代わりに、複数のサービスに対して外来の顧客要求を待つことができる.
inetdプロセスはdaemon_Init関数の説明のテクニックは自分を守護プロセスに変えます.
次に、自分のプロファイルを読み込み、処理します.通常は/etc/inetd.confのプロファイルは、このスーパーサーバがどのサービスを処理するか、および1つのサービス要求が到着したときにどのようにするかを決定します.このファイルの各行に含まれるフィールドは、次の図のようになります.
次はinetd.confファイルの例としてのいくつかの行:
次にinetdデーモンのワークフローを示します
 
1.起動時に/etc/inetdを読み込む.confファイルは、ファイルで指定したサービスごとに適切なタイプのソケットを作成します.新しく作成された各ソケットは、select呼び出しによって使用される記述子に追加されます.
2.ビット各ソケットはbindを呼び出し、対応するサーバをバンドルする周知のポートとプロビジョニングアドレスを指定する.ポート番号はgetservbynameで取得されます.
3.各TCPソケットについて、listenを呼び出して外部からの接続要求を受信する.UDPソケットについては、この手順は実行されません.
4.すべてのソケットを作成した後、selectを呼び出して、いずれかのソケットが読み取り可能になるのを待つ.
5.selectがソケットが読み取り可能であることを示すと、ソケットがTCPソケットであり、サーバのwait-flag値がnowaitである場合、acceptを呼び出してこの新しい接続を受け入れる.
6.inetdデーモンはfork派生プロセスを呼び出し、サブプロセスによってサービス要求を処理する.(サブプロセスはまず端末から離れ、execを呼び出して対応するserver-programフィールドで指定されたプログラムを実行して要求を具体的に処理する)
7.ステップ5でselectがバイトストリームソケットを返す場合、親プロセスは接続ソケットを閉じる必要があります(標準コンカレントサーバのように).親プロセスは、次の読み取り可能ソケットになるまでselectを再度呼び出します.
 
 
 
daemon_inetd関数
以下にdaemonという名前を示します.inetdの関数で、inetdによって起動された既知のサーバプログラムで使用できます.

 1 #include    "unp.h"
 2 #include    
 3 
 4 extern int    daemon_proc;    /* defined in error.c */
 5 
 6 void
 7 daemon_inetd(const char *pname, int facility)
 8 {
 9     daemon_proc = 1;        /* for our err_XXX() functions */
10     openlog(pname, LOG_PID, facility);
11 }

View Code
とdaemon_Initに比べて、すべてのデーモン化ステップはinetdによって開始時に実行されました.この関数のタスクは、エラー処理関数にdaemon_を設定するだけです.procフラグ、openlogを呼び出します
次にinetdがデーモンとして起動する時間取得サーバプログラムを示す

 1 #include    "unp.h"
 2 #include    
 3 
 4 int
 5 main(int argc, char **argv)
 6 {
 7     socklen_t        len;
 8     struct sockaddr    *cliaddr;
 9     char            buff[MAXLINE];
10     time_t            ticks;
11 
12     daemon_inetd(argv[0], 0);
13 
14     cliaddr = Malloc(sizeof(struct sockaddr_storage));
15     len = sizeof(struct sockaddr_storage);
16     Getpeername(0, cliaddr, &len);
17     err_msg("connection from %s", Sock_ntop(cliaddr, len));
18 
19     ticks = time(NULL);
20     snprintf(buff, sizeof(buff), "%.24s\r
", ctime(&ticks)); 21 Write(0, buff, strlen(buff)); 22 23 Close(0); /* close TCP connection */ 24 exit(0); 25 }

View Code
すべてのソケット作成コードが消えていることがわかります.これらのステップはinetdによって実行されます.
この例のプログラムを実行するには、まず、/etc/servicesファイルに下りて追加するように、本サービスに名前とポートを付けます.
mydaytime     9999/tcp

次に/etc/inetdに下りを加える.confファイル:
mydaytime stream tcp nowait andy /home/andy/daytimetcpsrv3 daytimetcpsrv3

次にinetdにSIGHUP信号を送信し、プロファイルを再読み込みするように通知します.
次にnetstatコマンドを実行して、inetdがTCPポート9999にリスニングソケットを作成したことを検証します.