文章目录
题目
创建一个守护进程 ,使用 Linux 信号机制,让守护进程退出。
代码
/*************************************************************************
> File Name: main.c
> Author: 杨永利
> Mail: 1795018360@qq.com
> Created Time: 2021年07月16日 星期五 18时38分59秒
************************************************************************/
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#define MAXFILE 3
// 创建守护进程
void init_daemon(void)
{
pid_t pid = 0;
int i = 0;
// 第一次 fork,使之成为守护进程
pid = fork();
if (pid < 0) {
// 判断返回值,fork 函数出错
perror("fork error.");
exit(1);
}
else if (pid > 0) {
// 父进程,退出
exit(0);
}
// 子进程
// 使子进程成为新的会话组长和进程组长,摆脱原会话控制,,摆脱原进程组控制, 摆脱控制终端控制
setsid();
// 改变工作目录,防止其他原因 ,导致工作目录不存在
// 第二次 fork,
pid = fork();
if (pid < 0) {
// 判断返回值,fork 函数出错
perror("fork error.");
exit(1);
}
else if (pid > 0) {
// 父进程,退出
exit(0);
}
//关闭打开的文件描述符,避免资源浪费
for (i = 0; i < MAXFILE; ++i) {
// close(i);
}
chdir("/");
// 重设文件权限掩码
umask(0);
return;
}
void mysighandler_t(int arg)
{
printf("收到信号 SIGUSR1 系统开始退出 \n");
exit(1);
}
int main(int argc, char const *argv[])
{
// 注册一个信号 : 告诉 linux 内核 当有信号 SIGUSR1 发给我的时候 , 请你调用这个 apimysighandler_t
signal(SIGUSR1, mysighandler_t);
//创建守护进程
init_daemon();
printf("守护进程启动...\n");
while (1)
{
sleep(5);
printf("程序正在后台运行...\n");
}
return 0;
}
知识回顾
守护进程
守护进程概念
守护进程:Daemon(精灵)进程,是 Linux 中的后台服务进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。一般采用以 d 结尾的名字。
创建守护进程模型
- 创建子进程,父进程退出
所有工作在子进程中进行形式上脱离了控制终端。 - 在子进程中创建新会话
setsid()
函数,使子进程完全独立出来,脱离控制。 - 改变当前目录为根目录
chdir()
函数,防止占用可卸载的文件系统,也可以换成其它路径。 - 重设文件权限掩码
umask()
函数,防止继承的文件创建屏蔽字拒绝某些权限,增加守护进程灵活性。 - 关闭文件描述符
继承的打开文件不会用到,浪费系统资源,无法卸载。 - 开始执行守护进程核心工作
- 守护进程退出处理程序模型
信号
信号:是进程间通信(IPC)方式之一。
信号机制
A 给 B 发送信号,B 收到信号之前执行自己的代码,收到信号后,不管执行到程序的什么位置,都要暂停运行,去处理信号,处理完毕再继续执行。与硬件中断类似——异步模式。但信号是软件层面上实现的中断,早期常被称为“软中断”。
每个进程收到的所有信号,都是由内核负责发送的。
信号名称 | 信号说明 | 默认处理 |
---|---|---|
SIGABRT | 由程序调用 abort时产生该信号。 程序异常结束。 | 进程终止并且产生core文件 |
SIGALRM | timer到期, 有alarm或者setitimer | 进程终止 |
SIGBUS | 总线错误,地址没对齐等。取决于具体硬件。 | 结束终止并产生core文件 |
SIGCHLD | 进程停止或者终止时,父进程会收到该信号。 | 忽略该信号 |
SIGCONT | 让停止的进程继续执行 | 继续执行或者忽略 |
SIGFPE | 算术运算异常,除0等。 | 进程终止并且产生core文件。 |
SIGHUP | 终端关闭时产生这个信号 | 进程终止 |
SIGILL | 代码中有非法指令 | 进程终止并产生core文件 |
SIGINT | 终端输入了中断字符ctrl+c | 进程终止 |
SIGIO | 异步I/O,跟SIGPOLL一样。 | 进程终止 |
SIGIOT | 执行I/O时产生硬件错误 | 进程终止并且产生core文件 |
SIGKILL | 这个信号用户不能去捕捉它。 | 进程终止 |
SIGPIPE | 往管道写时,读者已经不在了,或者往一个已断开数据流socket写数据。 | 进程终止 |
SIGPOLL | 异步I/O,跟SIGIO一样。 | 进程终止 |
SIGPROF | 有setitimer设置的timer到期引发 。 | 进程终止 |
SIGPWR | Ups电源切换时 | 进程终止 |
SIGQUIT | Ctrl+\,不同于SIGINT,这个是会产生core dump文件的。 | 进程终止并且产生core文件 |
SIGSEGV | 内存非法访问,默认打印出segment fault | 进程终止并且产生core文件 |
SIGSTOP | 某个进程停止执行,该信号不能被用户捕捉。 | 进程暂停执行 |
SIGSYS | 调用操作系统不认识的系统调用。 | 进程终止并且产生core文件 |
SIGTERM | 有kill函数调用产生。 | 进程终止 |
SIGTRAP | 有调试器使用,gdb | 进程终止并且产生core文件 |
SIGTSTP | Ctrl+z,挂起进程。 | 进程暂停 |
SIGTTIN | 后台程序要从终端读取成数据时。 | 进程暂停 |
SIGTTOU | 后台终端要把数据写到终端时。 | 进程暂停 |
SIGURG | 一些紧急的事件,比如从网络收到带外数据。 | 忽略 |
SIGUSR1 | 用户自定义信号 | 进程终止 |
SIGUSR2 | 用户自定义信号 | 进程终止 |
SIGVTALRM | 有setitimer产生。 | 进程终止 |