如何实现守护进程

  • 创建子进程,父进程退出。 (脱离控制终端),很自然地,子进程成了孤儿进程,被init进程收养。

  • 子进程中创建新会话。

我们先介绍下进程组的概念:

进程组是一个或者多个进程的集合,由进程组id来唯一标识,除了进程号PID之外,进程组ID也是一个进程的必备属性。
每个进程组都有一个组长进程,其组长进程的进程号PID等于进程组ID,且该进程ID不会因为组长进程的退出而受到影响。

会话期

会话组是一个或者多个进程组的集合,通常,一个会话开始于用户登录,终止于用户退出,在此期间用户运行的所有进程 都属于这个会话期。

Setid函数就是用于创建一个新的会话,并担任该会话组的组长,有三个作用,让进程摆脱原会话和进程组,终端的控制,使进程完全独立出来。

  • 由于fork()继承了父进程的工作目录,对以后的使用造成不便,所以我们要改变当前目录为根目录。
  • 关闭文件描述符。 (fork()继承过来的)

  • 重设文件权限掩码。因为由继承得来的文件模式屏蔽字可能会被设置为拒绝某些权限

    void daemonize()
    {
      pid_t pid;
    
      pid = fork();
    
      /* In case of fork is error. */
      if (pid < 0)
        {
          fprintf(stderr,"fork error.\n");
          exit(0);
        }
      /* In case of this is parent process. */
      if (pid != 0)
        exit (0);// 父进程退出
      /* Become session leader and get pid. */
      pid = setsid();
      if (pid == -1)
        {
          fprintf(stderr, "setsid failed..");
          exit(0);
        }
      /* Change directory to root. */
    
        chdir ("/");
    
      /* File descriptor close. */
      int fd;
      fd = open ("/dev/null", O_RDWR, 0);
      if(fd != -1)
        {
          dup2(fd, STDIN_FILENO);
          dup2(fd, STDOUT_FILENO);
          dup2(fd, STDERR_FILENO);//all the output to stdin&stdout&stderr will go into /dev/null now
          if(fd > 2)
            close(fd);
        }
    
      umask (0);
    }