守护进程(Daemon)

来源:互联网 发布:充值系统源码 编辑:程序博客网 时间:2024/05/22 06:52

Hello,地球人们,Val今天来给大家分享一下关于守护进程的一些知识^_^
1. 守护进程是什么?
守护进程也叫精灵进程(Daemon),是运行在后台的一种特殊进程。她独立于终端并且周期性地执行某种人物或者等待某些发生的事件。
Linux的大多数服务器就是用守护进程实现的,例如:Internet服务器 inetd,Web服务器httped等。同时守护进程完成许多系统任务。如,作业规划进程crond等。
特点:不受用户登录注销等动作的影响。
2. 创建守护进程
创建守护进程最关键的一步是调用setsid函数创建一个新的会话(session),并成为话首进程(session leader)。
函数 pid_t setsid(void);
该函数创建成功时返回新创建的Session的id(当前进程的id),出错返回-1。fork()创建进程,然后让父进程退出exit,在子进程里调用setsid()。
成功调用该函数的结果是:
(1)创建一个新的会话(Session ),当前进程称为会话的话首进程,当前进程的id就是Session的id。
(2)创建一个新的进程组,当前进程成为进程组的组长进程,当前进程id就是进程组的id。
(3)如果当前进程原本有一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进程。失去控制终端指,原来的控制终端仍是打开的,仍然可以读写,但只是一个普通的打开文件而不是控制终端了。

  1. 代码如何编写,关键步骤是哪些?
    创建守护进程
    *1.调用umask将文件模式创建屏蔽字设置为0
    *2.调用fork,父进程exit。(如果该守护进程是作为一条简单的shell命令启动的,那么父进程终止使得shell认为该命令执行完毕;保证子进程不是一个进程组的组长进程)。
    *3.调用setsid创建一个新会话。
    setsid使调用进程成为新会话的首进程;
    调用进程成为一个进程组的组长进程;
    调用进程没有控制终端(再次fork一次,保证daemon进程之后不会打开tty设备)。
    *4.当前工作目录改为根目录。
    *5.关闭不需要的文件描述符。
    *6.忽略SIGCHLD信号。
    4.写一个daemon函数创建守护进程
    代码如下:
#include <stdio.h>#include <signal.h>#include <unistd.h>#include <stdlib.h>#include <fcntl.h>#include <sys/stat.h>void creat_daemon(void) {       int i;        int fd0;         pid_t pid;        struct sigaction sa;         umask(0); //设置文件掩码为0          if( (pid = fork()) < 0 )         {         }         else if (pid != 0){        exit(0); //终止父进程         }         setsid(); //设置新会话        sa.sa_handler = SIG_IGN;          sigemptyset(&sa.sa_mask);        sa.sa_flags = 0;        if( sigaction(SIGCHLD, &sa, NULL ) < 0 )         { // 注册子进程退出忽略信号                    return;          }        if( (pid = fork())<0)          { //再次fork,终止父进程,保持子进程不是话⾸进程,从而保证后续不会在和其他终端关联              printf("fork error!\n");             return;          }         else if( pid != 0)         {           exit(0);          }         if( chdir("/") < 0 )          {//更改工作目录到根              printf("child dir error\n");              return;        }          close(0);          fd0 = open("/dev/null", O_RDWR);// 关闭标准输入,重定向所有标   准(输入输出错误)到/dev/null          dup2(fd0, 1);             dup2(fd0, 2);  }         int main()  {          creat_daemon();             while(1)        {         sleep(1);        } }

运行结果如下图:(请原谅我图片里的错误的单词,其实应该是daemon我却写错了这里写图片描述really,really sorry)
这里写图片描述
守护进程自成会话,自成进程组。
4.setsid()的作用是什么?
setsid()使得子进程成为会话组长(sid=pid),也是进程组组长(pgid==pid),并且脱离了原来的控制终端。所以,控制终端无论怎么操作,新的进程正常情况下不会收到它发来的信号。
5.umask(0)的作用:
子进程从父进程那里继承了一些东西,可能未把权限继承下来,所以要赋予它更高的权限,便于子进程操作。
6.chdir(“/”)作用:
进程活动时,其工作目录所在的文件系统不能卸下,一般需要将工作目录改变到根目录。
7.为什么创建守护进程时有人fork两次?
第一次fork为后面的setsid服务,setsid的调用者不能是进程组组长,而第一次调用的时候父进程是进程组组长。第二次调用后,把前面一次fork出来的子进程退出,这样第二次fork出来的子进程就和他们脱离了关系。其实第二次fork也不是必须的,也可以只fork一次,然后让父进程退出,子进程调用setsid,上面的代码例子就是后者。