1.什么是守护进程
守护进程也称精灵进程( Daemon),是运⾏在后台的⼀种特殊进程。它独⽴于控制终端并且周期性地执⾏某种任务或等待处理某些发⽣的事件。守护进程是⼀种很有⽤的进程。
Linux系统启动时会启动很多系统服务进程,这些系统服 务进程没有控制终端,不能直接和⽤户交互。其它进程都是在⽤户登录或运⾏程序时创建,在运⾏结束或⽤户注销时终⽌,但系统服务进程不受⽤户登录注销的影响,它们⼀直在运⾏着。这种进程有⼀个名称叫守护进程(Daemon)。
2.创建守护进程
守护进程自成会话,所以创建守护进程需要先创建一个会话。
创建守护进程最重要的一步是调用setsid()函数,创建一个新的会话,并成为话首进程。
1. 调⽤umask将⽂件模式创建屏蔽字设置为0.
2. 调⽤fork,⽗进程退出( exit) 。原因: 1)如果该守护进程是作为⼀条简单的shell命令启动的,那么⽗进程终⽌使得shell认为该命令已经执⾏完毕。 2)保证⼦进程不是⼀个进程组的组长进程。
3. 调⽤setsid创建⼀个新会话。 setsid会导致: 1)调⽤进程成为新会话的⾸进程。 2)调⽤进程成为⼀个进程组的组长进程 。 3)调⽤进程没有控制终端。(再次fork⼀次,保证daemon进程,之后不会打开tty设备)
4. 将当前⼯作⽬录更改为根⽬录。
5. 关闭不在需要的⽂件描述符。
6. 其他:忽略SIGCHLD信号。
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
void creat_daemon(void)
{
int i;
int fd0;
pid_t pid;
struct sigaction sa;
umask(0); //设置文件掩码为0
if( (pid = fork()) < 0 ){
}else if (pid != 0){
exit(0); //终止父进程
}
setsid(); //设置新会话
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if( sigaction(SIGCHLD, &sa, NULL ) < 0 ){ // 注册子进程退出忽略信号
return;
}
if( (pid = fork())<0){ //再次fork,终止父进程,保持子进程不是话⾸进程,从而保证后续不会在和其他终端关联
printf("fork error!\n");
return;
}else if( pid != 0){
exit(0);
}
if( chdir("/") < 0 ){//更改工作目录到根
printf("child dir error\n");
return;
}
close(0);
fd0 = open("/dev/null", O_RDWR); // 关闭标准输入,重定向所有标准(输入输出错误)到/dev/null
dup2(fd0, 1);
dup2(fd0, 2);
}
int main()
{
creat_daemon();
while(1)
{
sleep(1);
}
}
由结果可见多了一个会话,且与当前终端无关。
为什么有的fork一次,有的fork两次?
调用setsid()函数的进程不能是进程组组长进程,fork一次创建一个子进程,关闭父进程,子进程一定不是组长进程。
第二次fork,现在已经关闭了与终端的联系,但不可避免之后有可能创建与终端的联系。只有会话的话首进程才能创建与进程的联系。再次fork后,关闭父进程,子进程不是话首进程,所以在之后的操作中都不可能在与终端进行联系。保证了守护进程不是话首进程。