学习笔记
守护进程是一种长期运行的进程,这种进程在后台运行,且不和任何的控制终端关联。那么守护进程的前提条件是接触与终端的绑定,也就是说终端退出的时候不能影响该进程,而且守护进程要有自己的session并且是leader,那么要实现这一点就需要fork出子进程,使子进程代替原进程来创建session(原进程结束运行),然后通过setsid函数来创建session,这里需要将umask设为0(因为一般默认会是2,影响创建的文件的执行权限)。最后一步是屏蔽掉标准输入输出,/dev/null就相当于黑洞(垃圾箱),用dup2函数将标准输入输出的文件描述符指向这个空设备就可以了。
守护进程不会收到来自内核的SIGHUP信号,也就是说如果守护进程收到了SIGHUP信号,一定是其他的进程发送的,很多守护进程把这个信号作为通知信号,表示配置文件已经发生改动。同样也不会收到来自内核的SIGINT和SIGWINCH信号,因为守护进程与终端无关联。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int ngx_deamon(){
switch(fork()){ // fork子进程
case -1:
// 说明子进程创建失败 写一些日志文件
return -1;
case 0:
// 这里是子进程 直接break跳出switch
break;
default :
// 这里是父进程 直接结束
exit(0);
}
// 只有子进程可以走到这里
umask(0); // 设置umask值 确保创建文件的执行权限
if(setsid() == -1){ // 脱离父进程后 创建新的session 并成为leader
/// 创建session出错 写错误日志
return -1;
}
int fd = open("/dev/null", O_RDWR); // 打开空设备
if(fd == -1){
// 文件打开失败 写错误日志
return -1;
}
// 对于dup2函数 如果第二个参数不是新的文件描述符 会先close第二个参数的文件描述符 然后再复制
if(dup2(fd, STDIN_FILENO) == -1){ // 重定向标准输入到空设备
// 写错误日志
return -1;
}
if(dup2(fd, STDOUT_FILENO) == -1){ // 重定向标准输出到空设备
// 写错误日志
return -1;
}
if(fd > STDERR_FILENO){ // 这里的fd应该为3 STDERR_FILENO应该为2
if(close(fd) == -1){ // 关闭空设备文件描述符 目的是不占用系统资源
// 写错误日志
return -1;
}
}
return 1;
}
int main(int argc, char *const *argv)
{
if(ngx_deamon() != 1){
// 守护进程创建失败 失败后的处理
return 1;
}
while(1){
printf("ngx_deamon\n");
sleep(1);
}
return 0;
}