一、什么是守护进程
守护进程:
守护进程也称精灵进程,是运行在后台的一种特殊进程。守护进程独立于控制终端并且周期性的执行某种任务或者等待处理某些打算的事件。生存周期长,常常在系统引导装入的时候启动,仅仅在系统关闭的时候才终止,可认为守护进程目的就是防止终端产生的一些信号让进程退出。因为它们没有控制终端,所以说它们是在后台运行的,很多服务器的应用和守护进程都有关。
二、守护进程的特征
1、独立于控制终端(没有控制终端),终端名(tty)设置成问号(?)。
2、父进程是1号进程(init)所以守护进程是孤儿进程
3、自成会话、自成进程组。不与其他会话、进程组相互干扰(一般一个守护进程的进程ID,组ID,会话ID都相同)。
4、守护进程不受用户登录注销的影响,当你注销或者重登后,守护进程一直在运行。
5、命令以‘d’结尾,大多数的守护进程都以root特权运行。
三、创建守护进程
创建一个守护进程的步骤如下:
1、首先调用umask函数来设置文件的权限,这是因为守护进程可能会创建某些文件所以要设定特定的权限。
2、调用fork函数然后终止父进程。这是因为要调用setsid函数来创建会话,这个函数不能被组长进程调用,我们创建一个进程再让这个进程创建子进程,那么父进程一定是组长进程,这时让父进程终止掉那么就能保证子进程的父进程是1号进程了。
3、调用setsid函数创建一个新的会话,这样当前的子进程就是新会话的首进程,是新进程组的组长进程并且无控制终端。
4、将当前的目录设置成根目录。
5、关闭不需要的文件描述符,关闭从父进程继承的任何文件描述符。
6、开始执行新的守护进程。
守护进程的代码实现:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/stat.h>
void mydaemon()
{
umask(0);
if(fork() > 0)
{
exit(0);
}
setsid();
chdir("/");
close(0);
close(1);
close(2);
signal(SIGCHLD,SIG_IGN);
}
int main()
{
mydaemon();
while(1)
{
}
return 0;
}
四、fork两次创建守护进程
fork两次的步骤:
1、设置守护进程的权限
2、第一次fork保证调用setsid函数的时候,进程不是组长进程。
3、这里调用setsid函数切断了当前进程和控制终端的联系,下面创建的进程也会继承当前的进程与终端的联系。
4、第二次fork,保证守护进程不是当前会话的首进程,同时还要终止掉当前的进程。
5、设置守护进程的工作目录。
6、关闭文件描述符,忽略SIGCHLD信号。
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<signal.h>
#include<unistd.h>
void my_daemon()
{
umask(0);
if(fork() > 0)
{
exit(1);
}
setsid();
if(fork() > 0)
{
exit(1);
}
chdir("/");
close(0);
close(1);
close(2);
signal(SIGCHLD,SIG_IGN);
}
int main()
{
my_daemon();
while(1)
{
}
return 0;
}
五、一次fork与两次fork的区别
前面我们fork一次就是为了保证在调用setsid函数的时候该进程不是组长进程(setsid函数不允许组长进程调用),我们这时候创建出来的守护进程自成进程组、自成会话,所以作为一个会话的首进程具有打开一个控制终端的权利,如果它打开了一个控制终端,那么就和守护进程独立与控制终端相互矛盾,所以就有了fork两次。
fork两次保证了第二次fork出来的孙子进程不是会话的首进程,所以要终止掉儿子进程,此时会话的首进程被终止,这个会话中的其他进程没有打开控制终端的权利了。