守护进程也称精灵进程(Daemon),是运⾏在后台的一种特殊进程。它独⽴立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。它自成进程组,自成绘画,不受用户登录注销的影响。凡是TPGID⼀栏写着-1的都是没有控制终端的进程,也就是守护进程
创建一个守护进程需要调用setsid()函数:该函数调用成功时返回新创建的Session的id(其实也就是当前进程的id),出错返回-1。注意,调用这个函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。要保证当前进程不是进 程组的Leader也很容易,只要先fork再调⽤用setsid就⾏了。fork创建的子进程和父进程在同一个进 程组中,进程组的Leader必然是该组的第⼀个进程,所以子进程不可能是该组的第一个进程,在子 进程中调⽤用setsid就不会有问题了。
成功调⽤用该函数的结果是:
1. 创建⼀个新的Session,当前进程成为Session Leader,当前进程的id就是Session的id。
2. 创建一个新的进程组,当前进程成为进程组的Leader,当前进程的id就是进程组的id。
3. 如果当前进程原本有一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进程。所谓失去控制终端是指,原来的控制终端仍然是打开的,仍然可以读写,但只是⼀个普通的打开文件而不是控制终端了。
创建守护进程的步骤如下:
1、 调⽤用umask将⽂文件模式创建屏蔽字设置为0;
2、调⽤用fork,⽗父进程退出(exit);
3、在子进程中调用setsid()函数;
4、将当前⼯工作⽬目录更改为根⽬目录。
5、关闭不在需要的⽂文件描述符。
6、忽略SIGCHLD信号。
代码如下:
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdlib.h>
void mydaemon()
{
umask(0);、//步骤一
pid_t id = fork();
if(id>0)
{//father
exit(1);//步骤二
}
else
{//child
setsid();//步骤三
chdir("/");//步骤四
close(0);//步骤五
close(1);
close(2);
signal(SIGCHLD,SIG_IGN);//步骤六
}
}
int main()
{
mydaemon();
while(1);
return 0;
}
步骤二调用fork一次和两次有什么不同呢?
第一次fork的作用是为了后面的setsid服务,因为调用setsid函数的进程不能是进程组组长,如果不fork出子进程,则此时的父进程是进程组组长,就无法调用setsid。当子进程调用完setsid函数之后,子进程是会话组长也是进程组组长,并且脱离了控制终端,此时,不管控制终端如何操作,新的进程都不会收到一些信号使得进程退出。
再次fork,终⽌止⽗父进程,保持⼦子进程不是话⾸首进程,从⽽而保证后续不会在和其他终端关联。
第二次不是必须的,是可选的。