【Linux】守护进程

来源:互联网 发布:欧莱雅抗衰老知乎 编辑:程序博客网 时间:2024/06/06 03:24
1.守护进程的定义
服务进程不受用户登录注销的影响,且一直运行,这种进程有一个名称叫守护进程,也称精灵进程(Daemon)。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。
特点:
1). 7*24小时一直运行
2).不受用户登录注销影响,无控制终端
3).守护进程是孤儿进程,可以认为父进程是init
4).守护进程自成一个进程组,自成会话组,与其他会话互不干扰
5).命名总以D结尾
2.创建守护进程
在Unix环境中,守护进程的父进程通常是init进程,但并不总是这样。守护进程通常由一个父进程分派子进程创建,然后立即退出,从而导致init采用子进程,或者由init进程直接启动守护程序。
创建步骤:
1).调用umask将文件模式创建屏蔽字设置为0。
2).调用fork,父进程退出(exit)(确保子进程不是进程组的组长进程)
3).调用setsid创建一个新会话。
4).将当前工作目录更改为根目录。
5).关闭不在需要的文件描述符。
6).忽略SIGCHLD信号。
调用setsid时应注意:当前进程不能为该进程组的组长进程,因为setsid调用成功时会返回新创建的Session的id(其实也就是当前进程的id),出错返回-1。若当前进程是进程组的Leader,则调用出错。要避免这种情况就需要在fork()创建子进程之后父进程立即退出,就保证了以后的其他进程都不可能为该进程组的组长进程,调用就不会出错。
调用setsid的结果:
1)调用进程成为新会话的首进程。
2)调用进程成为一个进程组的组长进程 。
3)调用进程没有控制终端。(再次fork一次,保证daemon进程,之后不会打开tty设备)
代码:
 #include <stdio.h> #include <unistd.h> #include <stdlib.h>   void mydaemon() {      umask(0);       //屏蔽字设置为0      if(fork()>0)    //调用fork,父进程退出      {          exit(0);      }        setsid();       //创建一个新会话      chdir("/");     //将当前工作目录更改为根目录        close(0);       //关闭文件描述符      close(1);      close(2);  }    int main()  {      mydaemon();      while(1);      return 0;  }
查询:

直接调用系统的daemon函数创建守护进程
函数原型

参数:若两个参数都设为0,则将当前工作目录改为根目录下,文件描述符则写入/dev/null下(/dev/null,Linux下黑洞,写入这里面的内容都会被丢弃)。
 #include <stdio.h> #include <unistd.h> int main()  {      daemon(0,0);      while(1);      return 0;  }
运行结果:

3.两次fork()调用与一次有何区别?
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <signal.h> void mydaemon() {      umask(0);       //屏蔽字设置为0      if(fork()>0)    //调用fork,父进程退出      {         exit(0);      }        setsid();       //创建一个新会话      if(fork()>0)      {          exit(1);      }      chdir("/");     //将当前工作目录更改为根目录        close(0);       //关闭文件描述符      close(1);      close(2);        signal(SIGCHLD,SIG_IGN);  }    int main() {      mydaemon();      //daemon(0,0);      while(1);      return 0;  }

第一次调用fork(),若该进程作为一条简单的shell命令启动的,那么父进程终止使得shell认为该命令已经执行完毕,保证了子进程不是进程组的组长进程。
第一次fork()出来的守护进程的pid,pgid和sid都相同,表明了守护进程自成会话组,自成进程组。而经过两次fork()调用,pid和pgid、sid已经不同,表示该进程属于某一个会话组,而不是会话首进程,避免了因误操作而重新打开终端。所以两次fork()更加安全。