【Linux】:守护进程化
朋友们、伙计们,我们又见面了,本期来给大家带来守护进程相关的知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!
C 语 言 专 栏:C语言:从入门到精通
数据结构专栏:数据结构
个 人 主 页 :stackY、
C + + 专 栏 :C++
Linux 专 栏 :Linux
目录
1. 守护进程
1.1 进程组与会话
2. 实现守护进程
1. 守护进程
我们之前实现的网络服务(udp、tcp)不能直接在bash中以前台进程的方式直接运行,真正的服务器必须在Linux后台以守护进程(精灵进程)的方式运行!不受用户登陆和注销的影响
1.1 进程组与会话
在实现守护进程之前我们先来了解一组概念:
进程组、会话、作业
我们可以在bash启动一条命令来看一下这组概念:
同样的我们也可以查看一下bash的进程组与会话:
所以通过上面的例子就可以看出来:
- PID == PGID是自成一个进程组,并且进程组默认一定是在一个会话中的;
- bash是自成进程组,自成会话
那么如果我们同时启动多个进程呢:
- 同时启动多个进程时,这些进程是可以属于一个进程组的,组ID一般是第一个进程组ID
- 每次我们登录Linux时,OS都会给我们提供一个bash,然后提供一个终端,为我们提供解析命令行服务,这些都叫做一个会话;
- 在命令行启动的所有进程,最终默认都是在当前会话内部的一个进程组(也可以是一个进程一个进程组)。
通过结合我们之前在信号部分提到的前台进程与后台进程可以得出一个结论:
- 任何时刻,一个会话内部,可以以有多个进程组(用户级任务),但是默认任何时刻,都只允许一个进程组在前台(前台进程组)
- 会话和会话之前是具有隔离性的
在命令行启动命令时只需要在后面加上 & 既可以将其以后台进程的方式启动;
使用jobs可以查看当前会话的进程组:
我们已经运行起来的进程可以使用ctrl + z来停止然后将其放到后台:
通过fg + 任务编号可以将指定的任务放到前台:
通过bg + 任务编号可以将指定的任务在后台运行起来:
这些命令在前面的部分都已经提到过了,这里就不做过多解释了;
2. 实现守护进程
结合进程组和会话的概念,守护进程其实就是一个独立的会话,不隶属于任何一个bash的会话:
实现守护进程的接口是:
他有一个前提条件是:
调用他的进程不能是一个进程组的组长,但是多个进程中,第一个是组长,单进程中自己也是组长,所以要实现守护进程,就必须要创建子进程,然后直接关闭父进程,此时的子进程就可以成为守护进程,换句话说,守护进程其实就是孤儿进程;
实现守护进程一般分为五步:
- ① 忽略可能引起进程异常退出的信号
- ② 让自己不要成为组长(fork)
- ③ 使用setsid接口;
- ④ 是否将自己的当前目录(CWD)更改为根目录(为了方便以根目录直接查找各种资源)
- ⑤ 是否需要关联用户的输入输出以及错误信息
Daemon.hpp:
#pragma once #include <iostream> #include <cstdlib> #include <signal.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> const char* root = "/"; const char *dev_null = "/dev/null"; void Daemon(bool ischdir, bool isclose) { // 1. 忽略可能引起进程异常终止的信号 signal(SIGCHLD, SIG_IGN); signal(SIGPIPE, SIG_IGN); // 2. 让自己不要成为组长 if (fork() > 0) exit(0); // 3. 守护进程 // 设置让自己成为一个新的会话, 后面的代码其实是子进程在执行 setsid(); // 4. 是否更该CWD if (ischdir) { chdir(root); } // 5. 已经变成守护进程,此时就不需要和用户的输入输出,错误进行关联了 if (isclose) { close(0); close(1); close(2); } else { // 一般建议使用这种方案 int fd = open(dev_null, O_RDWR); if (fd > 0) { dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); close(fd); } } }
Main.cc:
#include "Daemon.hpp" #include <unistd.h> int main() { // 变成守护进程 Daemon(true, false); // 需要执行的核心代码 while (1) { sleep(1); } return 0; }
测试结果:
同样的我们也可以对我们之前实现的udp和tcp代码进行守护进程化,在初始化之前将程序设置为守护进程即可:
tcp守护进程化源码:
https://gitee.com/yue-sir-bit/linux/tree/master/4.tcp_server_echo