守护进程 | |
---|---|
特点 | 后台服务进程 独立于控制终端 周期性执行某任务 不受用户登录注销影响 一般采用以 d 结尾的名字 (服务) |
进程组 | 组长: 第一个进程 进程组ID: 组长的ID |
会话 (多个进程组) | 创建会话: * 不能是进程组长 * 创建会话的进程成为新进程组的组长 * 部分Linux发行版需要root * 创建出的新会话会丢弃原有的控制终端 * 一般步骤:fork()在\创建子进程,父进程死,子进程执行创建会话操作 创建会话: setsid() 获取所属会话ID: getsid() |
创建守护进程的模型 | fork()子进程,父进程退出 子进程创建信会话 更改当前工作目录 chdir 重设文件掩码 关闭文件描述符 执行核心工作 |
/**
* @author IYATT-yx
* @brief 将当前系统时间写入文件
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/time.h>
#include <stdbool.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
// 捕捉到信号后,被执行的回调函数
// 获取系统当前时间,并写入 /tmp/currentTime
void saveTime(int no)
{
if (no == SIGALRM)
{
time_t currentTime;
time(¤tTime);
const char *timeStr = ctime(¤tTime);
int fd = open("/tmp/currentTime", O_WRONLY | O_CREAT, 0664);
write(fd, timeStr, strlen(timeStr));
close(fd);
}
}
int main(void)
{
pid_t pid = fork();
if (pid > 0)
{
return 0;
}
else if (pid == 0)
{
// // // // // // // // //
// 创建守护进程的常用模型 //
// // // // // // // // //
// 创建会话
// 修改工作目录,不依赖运行时的路径
// 修改掩码,置为 0, 则进程创建文件时,设置的权限即为创建出的文件实际的权限 (创建文件设置的权限 & ~umask)
// 关闭默认文件描述符
setsid();
chdir("/home");
umask(0);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// 注册信号捕捉
struct sigaction sig;
sig.sa_handler = saveTime;
sig.sa_flags = 0;
sigemptyset(&sig.sa_mask);
sigaction(SIGALRM, &sig, NULL);
// 定时器
struct itimerval val;
// 首次
val.it_value.tv_sec = 1;
val.it_value.tv_usec = 0;
// 周期
val.it_interval.tv_sec = 1;
val.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &val, NULL);
while (true)
{
sleep(1);
}
}
}