zoukankan      html  css  js  c++  java
  • Linux守护进程

    守护进程(daemon)是在后台运行且不与任何控制终端关联的进程。

    与终端脱离有两个目的:

    1. 避免进程运行过程中将信息输出到终端
    2. 避免进程被终端产生的信息中断

    创建守护进程前首先需要理解几个概念:进程组会话控制终端

     

    每个进程除了有一进程ID(PID)之外,还属于一个进程组。

    进程组是一个或多个进程的集合,每个进程组有一个进程组ID。

    每个进程组有一个组长进程(process group leader),组长进程的PID等于它的进程组ID。

    会话(session)是一个或多个进程组的集合。

    会话中的多个进程组可被分为一个前台进程组以及多个后台进程组。

    一个会话有一个控制终端。

     

    进程可以通过调用setsid函数创建一个新会话。

    pid_t setsid(void);

    有一点需要注意:调用此函数的进程不能是一个进程组的组长。调用该函数会发生以下3件事:

    (1) 该进程变成新会话的会话首进程(session leader)

    (2) 该进程成为一个新进程组的组长进程

    (3) 该进程没有控制终端

    创建守护进程的步骤如下:

    (1) 创建子进程,父进程退出

        调用fork,然后父进程exit,这么做实现下面两点:第一、如果本进程是从前台作为一个shell命令启动的,当父进程终止时,shell就认为该命令已经执行完毕,这样子进程就自动在后台运行。第二、子进程继承了父进程的进程组ID,而且它有自己的进程ID,这就保证子进程不是一个进程组的组长进程,这是接下去调用setsid函数的必要条件。

    (2) 调用setsid创建一个新会话

        步骤1中的子进程继承了父进程的进程组、会话、控制终端,调用setsid函数会创建新的会话、新的进程组,而且没有控制终端。

    (3) 忽略SIGHUP信号并再次fork

        步骤2中的子进程是一个会话首进程,当没有控制终端的会话首进程打开一个终端设备时,该终端自动成为这个会话首进程的控制终端。再次fork可以确保新的子进程不再是一个会话首进程,从而不能自动获得一个控制终端。这里必须忽略SIGHUP信号,因为当会话首进程终止时,其会话中的所有进程(包括再次fork产生的子进程)都会受到SIGHUP信号。

    (4) 将当前工作目录更改为根目录

    (5) 重设文件权限掩码

    (6) 关闭所有打开的文件描述符 

    (7) 重定向stdin、stdout、stderr

    下面给一个具体的例子:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <signal.h>
    #include <time.h>
    
    #define    MAXFD    64
    
    void daemon_init() {
        pid_t pid;
        if ( (pid = fork()) < 0) {
            perror("fork error");
            exit(1);
        } else if (pid){
            exit(0);
        }
        // child 1
        if (setsid() < 0) {
            perror("setsid error");
            exit(1);
        }
        signal(SIGHUP, SIG_IGN);
        if ( (pid = fork()) < 0) {
            exit(1);
        } else if (pid){
            exit(0);
        }
        // child 2
        chdir("/");
        umask(0);
        for (int i = 0; i < MAXFD; i++) {
            close(i);
        }
        open("/dev/null", O_RDONLY);
        open("/dev/null", O_RDWR);
        open("/dev/null", O_RDWR);
    }
    
    int main(int argc, char **argv) {
        
        daemon_init();
        
        FILE *fp;
        time_t t;
        while (true) {
            if ( fp = fopen("/tmp/daemon.log", "a") ) {
                t = time(0);
                fprintf(fp, "current time is: %s", asctime(localtime(&t)));
                fclose(fp);
            }
            sleep(1);
        }
    } 

    参考文章:

    Linux进程关系

    守护进程

    守护进程的创建方法和步骤

    linux系统编程之进程(八):守护进程详解及创建,daemon()使用

  • 相关阅读:
    centos 7.0 yum 分开安装 LAMP 环境 +zabbix3.4环境
    互联网产品接入支付功能如何测试?
    python实现:将文本文件分割成多个小文本文件(php也可实现)
    『危机领导力』告诉我们如何带好团队
    Fiddler显示服务器IP的方法
    Google PageSpeed Tools 性能测试分析
    写给浮躁的测试工程师一封信
    数据库事务和锁
    测试工作中ADB命令实战
    git使用基础
  • 原文地址:https://www.cnblogs.com/gattaca/p/6413257.html
Copyright © 2011-2022 走看看