守护进程也被叫做精灵进程,是运行在后台的一种特殊进程。
他独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程,Linux的大多数服务器就是用守护进程实现的。比如ftp服务器,ssh服务器,Web服务器http等,同时,守护进程完成许多系统任务,比如,作业规划进程crond等。
Linux系统启动时会启动很多系统服务进程,这些系统服务进程没有控制终端,不能直接和用户直接进行交互。其他进程都是在用户登录或运行程序时创建,在运行结束或用户注销是终止,但系统服务进程(守护进程)不受用户登录注销的影响,他们一直在运行着,这种进程就叫做守护进程(Daemon)
创建守护进程
创建守护进程最关键的一步就是调用setsid函数创建一个新的Session,并成为Session Leader。
#include<unistd.h>
pid_t setsid(void);
调用成功返回新创建的Session的ID(也就是当前进程的ID),出错返回-1
调用该函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。要保证做到这一点,只要我们先fork再调用setsid就行了。fork创建的子进程和父进程在同一个进程组中,进程组的Leader必定是该组的第一个进程,子进程不可能是该组的第一个进程,在子进程中调用setsid就可以了。
成功调用该函数的结果是:
(1)创建一个新的Session,当前进程成为Session Leader,当前进程的ID就是Session的ID
(2)创建一个新的进程组,当前进程成为进程组的Leader,当前进程的ID就是进程组的ID
(3)如果当前进程原本有一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进程,失去控制终端是指原来的控制终端依然打开,任然可以读写,但只是一个普通的打开文件而不是控制终端了
#include <stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/stat.h>
void mydaemon()
{
pid_t pid;
//调用umask将文件模式创建屏蔽字设置为0
umask(0);
//调用fork,父进程退出(exit)
//如果该守护进程是作为一条简单的shell命令启动的
//那么父进程终止使得shell认为该命令已经执行完毕
//
//保证子进程不是一个进程组的组长进程
if((pid = fork()) < 0)
{
perror("fork");
}
else if(pid > 0)
{
//终止父进程
exit(0);
}
//调用setsid创建一个新会话
setsid();
//忽略SIGCHLD信号
signal(SIGCHLD,SIG_IGN);
//将当前工作目录更改为根目录
if(chdir("/") < 0)
{
perror("chdir");
return;
}
//关闭不再需要的文件描述符
close(0);
}
int main()
{
mydaemon();
while(1);
return 0;
}
只要TPGID为-1就说明该进程为守护进程。至此我们就使用setsid函数创建了一个守护进程。
daemon函数
#include <unistd.h>
int daemon(int nochdir, int noclose);
1. daemon()函数主要用于希望脱离控制台,以守护进程形式在后台运行的程序。
2. 当nochdir为0时,daemon将更改进程的根目录为 /
3. 当noclose为0是,daemon将进程的STDIN, STDOUT, STDERR都重定向到/dev/null。
#include <stdio.h>
#include<unistd.h>
int main()
{
daemon(0,0);
while(1);
return 0;
}
我们可以看到,使用daemon函数也可以创建出一个守护进程。