Linux守护进程

守护进程是做服务器必备的知识了,这里总结一下。

什么是守护进程?

Daemon(精灵)进程,是 Linux 中的后台服务进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。一般采用以 d 结尾的名字。

Linux 后台的一些系统服务进程,没有控制终端,不能直接和用户交互。不受用户登录、注销的影响,一直在运行着,他们都是守护进程。如:预读入缓输出机制的实现;ftp 服务器;nfs 服务器等。

创建守护进程,最关键的一步是调用 setsid 函数创建一个新的 Session,并成为 Session Leader。

需要的前置知识

进程组,也称之为作业。BSD 于 1980 年前后向 Unix 中增加的一个新特性。代表一个或多个进程的集合。每个进程都属于一个进程组。在 waitpid 函数和 kill 函数的参数中都曾使用到。操作系统设计的进程组的概念,是为了简化对多个进程的管理。

当父进程,创建子进程的时候,默认子进程与父进程属于同一进程组。进程组 ID==第一个进程 ID(组长进程)。

所以,组长进程标识:其进程组 ID==其进程 ID

可以使用 kill -SIGKILL -进程组 ID(负的)来将整个进程组内的进程全部杀死。组长进程可以创建一个进程组,创建该进程组中的进程,然后终止。只要进程组中有一个进程存在,进程组就存在,与组长进程是否终止无关。进程组生存期:进程组创建到最后一个进程离开(终止或转移到另一个进程组)。

一个进程可以为自己或子进程设置进程组 ID

相关函数

setsid 函数

创建一个会话,并以自己的 ID 设置进程组 ID,同时也是新会话的 ID。pid_t setsid(void); 成功:返回调用进程的会话 ID;失败:-1,设置 errno

调用了 setsid 函数的进程,既是新的会长,也是新的组长。

getsid 函数

获取进程所属的会话 ID;  pid_t getsid(pid_t pid); 成功:返回调用进程的会话 ID;失败:-1,设置 errno

pid 为 0 表示察看当前进程 session ID

ps ajx 命令查看系统中的进程。参数 a 表示不仅列当前用户的进程,也列出所有其他用户的进程,参数 x 表示不仅列有控制终端的进程,也列出所有无控制终端的进程,参数 j 表示列出与作业控制相关的信息。

组长进程不能成为新会话首进程,新会话首进程必定会成为组长进程。

创建会话
创建一个会话需要注意以下 6 点注意事项:
1. 调用进程不能是进程组组长,该进程变成新会话首进程(session header)
2. 该进程成为一个新进程组的组长进程。
3. 需有 root 权限 (ubuntu 不需要)
4. 新会话丢弃原有的控制终端,该会话没有控制终端
5. 该调用进程是组长进程,则出错返回
6. 建立新会话时,先调用 fork, 父进程终止,子进程调用 setsid()

创建守护进程模型

1. 创建子进程,父进程退出
  所有工作在子进程中进行形式上脱离了控制终端
2. 在子进程中创建新会话
  setsid()函数
  使子进程完全独立出来,脱离控制
3. 改变当前目录位置
  chdir()函数
  防止占用可卸载的文件系统
  也可以换成其它路径
4. 重设文件权限掩码
  umask()函数
  防止继承的文件创建屏蔽字拒绝某些权限
  增加守护进程灵活性
5. 关闭文件描述符
  继承的打开文件不会用到,浪费系统资源,无法卸载
6. 开始执行守护进程核心工作守护进程退出处理程序模型

 1 #include<stdio.h>
 2 #include<sys/stat.h>
 3 #include<fcntl.h>
 4 #include<stdlib.h>
 5 #include<string.h>
 6 #include<unistd.h>
 7 #include<errno.h>
 8 #include<pthread.h>
 9 
10 void sys_err(const char *str) {
11     perror(str);
12     exit(1);
13 }
14 
15 int main(int argc,char *argv[])
16 {
17     pid_t pid;
18     int ret,fd;
19 
20     //Step1:创建子进程,父进程终止
21     pid=fork();
22     if (pid>0) exit(0);
23 
24     //Step2:子进程中创建新会话
25     pid=setsid();
26     if (pid==-1)
27         sys_err("setsid error");
28 
29     //Step3:改变当前目录位置,防止目录在可卸载的文件内
30     ret=chdir("./");
31     if (ret==-1)
32         sys_err("chdir error");
33 
34     //Step4:重设文件权限掩码umask,防止权限被拒绝
35     umask(0023);
36 
37     //Step5:
38     //关闭文件描述符0,没有标准输入
39     //重定向 标准输出和错误输出 到指定文件 
40     close(STDIN_FILENO);
41     fd=open("/dev/null",O_RDWR);        //此时fd应为0,因为open寻找最小的文件描述符
42     if (fd==-1)
43         sys_err("open error");
44     dup2(fd,STDOUT_FILENO);
45     dup2(fd,STDERR_FILENO);
46 
47     //Step6:守护进程逻辑
48     while(1);
49     
50     return 0;
51 }
原文地址:https://www.cnblogs.com/clno1/p/12941308.html