【Linux】进程篇(补):守护进程
文章目录
- 1. 补充
- 1.1 查看
- 1.2 控制进程组的方式
- 2. 创建守护进程
- step1. 忽略信号
- step2. 让自己不是组长
- step3. setsid 函数:给调用函数设置新的会话和进程组 ID
- step4. chdir 函数:可以改变守护进程的工作路径
- step5. 处理文件描述符 0、1、2
- 守护进程类样例
1. 补充
1.1 查看
为了观察进程,我们以在命令提示符处,运行 sleep 命令为例。
ps axj | head -1 && ps axj | grep sleep | grep -v grep
- 得到的信息:
-
PPID
:父进程 ID -
PID
:进程 ID -
PGID
:进程组 -
SID
:会话 ID -
TTY
:进程关联的终端
每登录一次,都是一个新的会话,即每个会话关联一个终端文件,进程组的名称是进程组中第一个进程的 PID。
- 进程组,分为前台任务和后台任务
- 在会话中,只能有一个前台任务在运行
(解释了我们在命令行启动一个进程的时候,bash 就无法工作了的原因) - 每次登录就是创建一个新的会话、bash 任务;启动进程,就是在当前会话中创建一个后台任务;退出会话,会影响会话内部的所有任务
- 一般网络服务器,为了不受到用户的登陆注销的影响,网络服务器会以 守护进程 的方式运行!
1.2 控制进程组的方式
jobs
:查看自己会话中后台运行的进程
fg [任务号]
:将相应进程提到前台
ctrl + Z
:将前台运行的进程暂停,并放入后台
bg [任务号]
:运行后台暂停的进程
2. 创建守护进程
为了不受用户影响,网络服务器会将其进程单独拎出来,使用新的会话和进程组,为此称守护进程
step1. 忽略信号
signal(SIGPIPE, SIG_IGN);
signal(SIGCHLD, SIG_IGN);
// ...
step2. 让自己不是组长
要设置新的会话和进程组 ID,需要使用 setsid 接口,而每个进程组的组长(进程组号同自己 PID 的进程)是不能舍自己进程组不顾的,即使用 setsid 创建新组,必须不能是组长。
if (fork() > 0) exit(0);
-
fork出多进程,让父进程退掉,子进程继续跑,就相当于让出了组长。
-
本质上,守护进程就是 孤儿进程 的一种
step3. setsid 函数:给调用函数设置新的会话和进程组 ID
#include <unistd.h>pid_t setsid(void);
返回值:
- 成功返回新的进程组 ID,失败返回 -1,并设置错误码
注意:组长是不能使用该接口的
step4. chdir 函数:可以改变守护进程的工作路径
非必要步骤
#include <unistd.h>int chdir(const char *path);
返回值:
- 成功返回 0,失败返回 -1,并设置错误码
step5. 处理文件描述符 0、1、2
这里的处理是将这些文件重新向到 /dev/null
中,目的是切断新会话和键盘等的联系。
这里的 /dev/null 是一个字符设备,传进的数据都会被直接丢弃。
守护进程类样例
#include <cstdlib>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>void Daemon()
{// 1. 忽略信号signal(SIGPIPE, SIG_IGN);signal(SIGCHLD, SIG_IGN);// 2. 让自己不要成为组长if (fork() > 0)exit(0);// 3. 新建会话,自己成为会话的话首进程pid_t ret = setsid();if ((int)ret == -1){// 日志或打印exit(1);}// 4. 可选:可以更改守护进程的工作路径// chdir("/")// 5. 处理后续的对于0,1,2的问题int fd = open("/dev/null", O_RDWR);if (fd < 0){// 日志或打印exit(2);}dup2(fd, 0);dup2(fd, 1);dup2(fd, 2);close(fd);
}
🥰如果本文对你有些帮助,请给个赞或收藏,你的支持是对作者大大莫大的鼓励!!(✿◡‿◡) 欢迎评论留言~~