2012年3月29日木曜日

[C 语言] daemon 守护进程

daemon (守护) 程序编写规则:
1. 程序运行后调用 fork, 并让父进程退出, 子进程获得一个新的进程 ID, 但继承了父进程的进程组 ID
2. 调用 setsid 创建一个新的 session, 使自己成为新 session 和新进程组的 leader, 并使进程没有控制终端 (tty)
3. 改变当前工作目录至根目录, 以免影响可加载文件系统, 或者也可以改变到某些特定的目录
4. 设置文件创建 mask 为 0, 避免创建文件时权限的影响
5. 关闭不需要的打开文件描述符, 因为 daemon 程序在后台执行, 不需要于终端交互, 通常就关闭 STDIN, STDOUT 和 STDERR, 其它根据实际情况处理, 另一个问题是 daemon 程序不能和终端交互, 也就无法使用printf方法输出信息了, 可以使用 syslog 机制来实现信息的输出, 方便程序的调试

程序运行后使用 ps 命令查看
$ ps axj | grep a.out
PPID   PID   PGID   SID   TTY  TPGID STAT   UID   TIME COMMAND
1      10118 10118  10118 ?       -1 Ss     505   0:00 ./a.out

例子:
================================================================================
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <syslog.h>
#include <signal.h>

int main(void)
{
    if(daemon_init() == -1) {
        printf("can't fork self/n");
        exit(0);
    }
    openlog("daemontest", LOG_PID, LOG_USER);
    syslog(LOG_INFO, "program started.");
    signal(SIGTERM, sig_term); /* arrange to catch the signal */
    while(1) {
        sleep(1); /* put your main program here */
    }
    return(0);
}

int daemon_init(void)
{
    pid_t pid;
    if((pid = fork()) < 0)
        return(-1);
    else if(pid != 0)
        exit(0); /* parent exit */
    /* child continues */
    setsid(); /* become session leader */
    chdir("/"); /* change working directory */
    umask(0); /* clear file mode creation mask */
    close(0); /* close stdin */
    close(1); /* close stdout */
    close(2); /* close stderr */
    return(0);
}

void sig_term(int signo)
{
    if(signo == SIGTERM)
        /* catched signal sent by kill(1) command */
    {
        syslog(LOG_INFO, "program terminated.");
        closelog();
        exit(0);
    }
}
================================================================================

0 件のコメント:

コメントを投稿