目录
守护进程相关的概念
进程组
多个进程在同一个组,第一个进程默认是进程组的组长
比如说,一个父进程创建了n个子进程,那么这些进程就是一个进程组,那么其中的父进程,就是这个进程组的"组长",引入这个概念就是为了方便管理进程,比如,可以使用kill -SIGKILL -进程组ID(负的)来将整个进程组内的进程全部杀死。
会话
进程组的更高一级,多个进程组对应一个会话。
创建会话的时候,组长不可以创建,必须是组员创建。
多个进程组组成一个会话,可以是每个进程组负责项目的某一个模块,然后,一个会话就是一个项目。父进程不能创建会话,子进程(其父进程还得先死了)创建会话的进程,称之为"会长",需要注意的是:
- 调用进程不能是进程组组长,该进程变成新会话首进程(session header)
- 该进程成为一个新进程组的组长进程。
- 新会话丢弃原有的控制终端,该会话没有控制终端
- 该调用进程是组长进程,则出错返回
- 建立新会话时,先调用fork, 父进程终止,子进程调用setsid
守护进程
脱离终端控制,在后台运行,周期执行一系列任务的进程
守护进程是与终端没有关系的(比如说,在终端随便启动一个程序,如果把终端关了,拿启动的程序进程就会终止了,而守护进程不一样,即便把终端给关了,也不会终止进程),
Daemon(精灵)进程,是Linux中的后台服务进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。一般采用以d结尾的名字。
Linux后台的一些系统服务进程,没有控制终端,不能直接和用户交互。不受用户登录、注销的影响,一直在运行着,他们都是守护进程。如:预读入缓输出机制的实现;ftp服务器;nfs服务器等。
创建守护进程,最关键的一步是调用setsid函数创建一个新的Session(会话),并成为Session Leader。
创建守护进程模型的步骤
step1: 创建子进程,父进程退出
所有工作在子进程中进行形式上脱离了控制终端
step2: 在子进程中创建新会话
setsid()函数(子进程当会长)
使子进程完全独立出来,脱离控制(类似于通过U盘启动的程序一旦运行后,把U拔出,也是可以运行的状况)
step3: 改变当前目录为根目录
chdir()函数(设置掩码)
防止占用可卸载的文件系统
也可以换成其它路径
step4: 重设文件权限掩码
umask()函数
防止继承的文件创建屏蔽字拒绝某些权限
增加守护进程灵活性
step5: 关闭文件描述符
继承的打开文件不会用到,浪费系统资源,无法卸载(调试的时候最好别关,关了啥也看不见了,最好,都调试没问题了,再把这步给加上)
step6: 开始执行守护进程核心工作
step7: 守护进程退出处理程序模型
创建一个守护进程
实现功能:每分钟在$HOME/log/ 创建一个文件, 文件格式: 程序名.时间戳
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>
#include <time.h>
#define _FILE_NAME_FORMAT_ "%s/log/mydaemon.%ld" //定义文件格式化
void touchfile(int num)
{
char *HomeDir = getenv("HOME");
char strFilename[256]={0};
sprintf(strFilename,_FILE_NAME_FORMAT_,HomeDir,time(NULL));
int fd = open(strFilename,O_RDWR|O_CREAT,0666);
if(fd < 0){
perror("open err");
exit(1);
}
close(fd);
}
int main()
{
// 创建子进程,父进程退出
pid_t pid = fork();
if(pid > 0){
exit(1);
}
// 当会长
setsid();
// 设置掩码
umask(0);
// 切换目录
chdir(getenv("HOME"));//切换到家目录
// 关闭文件描述符
//close(1),close(0),close(2);
// 执行核心逻辑
//struct itimerval myit ={{60,0},{60,0}};
struct itimerval myit ={{60,0},{1,0}};
setitimer(ITIMER_REAL,&myit,NULL);
struct sigaction act;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
act.sa_handler = touchfile;
sigaction(SIGALRM,&act,NULL);
while(1){
//每隔1分钟在/home/itheima/log 下创建文件
sleep(1);
//do sth
}
// 退出
return 0;
}
以上就可以实现,每分钟在$HOME/log/ 创建一个文件,达到不管终端关不关(稳定的在后台持续运行),都一直运行的状态。
守护进程扩展了解
背景:有时候写一个小程序,不需要上面的那么复杂,直接用下面的指令一执行,就达到了后台运行的效果了。
可以阻塞信号"SIGHUP" :"nohup"
通过 nohup指令也可以达到守护进程创建创建的效果
nohup cmd [> 1.log] &
- nohup 指令会让cmd收不到SIGHUP信号
- & 代表后台运行
nohub ./a.out &