1、概念
守护进程是脱离于终端并且在后台进行的进程。守护进程脱离于终端是为了避免进程在执行过程中的信息在任何终端上显示并且进程也不会被任何终端所产生的终端信息所打断。
守护进程独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件,通以d(daemon)结尾命名的进程就是守护进程啦,如作业规划进程crond、打印进程lqd等。
2、创建守护进程步骤
a、创建子进程,父进程退出(fork函数实现)
b、在子进程中创建新会话(setsid函数实现)
进程组:是一个或多个进程的集合。进程组由进程组ID来唯一标识,除了进程号(PID)之外,进程组ID也是一个进程的必备属性。每个进程组都有一个组长进程,其组长进程的进程号等于进程组ID,且该进程组ID不会因组长进程的退出而受到影响。
会话周期:会话期是一个或多个进程组的集合。通常,一个会话开始与用户登录,终止于用户退出,在此期间该用户运行的所有进程都属于这个会话期。
setsid函数用于创建一个新的会话,并担任该会话组的组长。调用setsid的三个作用:让进程摆脱原会话的控制,让进程摆脱原进程组的控制,让进程摆脱原控制终端的控制。
c、改变当前目录为根目录(chdir函数实现)
让守护进程工作在指定的目录。
d、重设文件权限掩码(umask实现)
文件权限掩码是指屏蔽掉文件权限中的对应位。此时通过umask(0)设置即可。
e、关闭文件描述符(close实现)
守护进程不会输入、输出、报错。即关掉STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO描述符字。
3、一个例子实现代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<sys/stat.h>
#define MAXFILE 65535
int main(){
pid_t pc;
int i,fd,len;
char *buf="this is a Daemon.\n";
len=strlen(buf);
pc=fork();//first step
if(pc<0){
printf("error fork()\n");
exit(1);
}else if(pc>0){
exit(0);
}
setsid();//second step
chdir("/");//third step
umask(0);//fourth step
for(i=0;i<3;++i){//fifth step
close(i);
}
while(1){
if((fd=open("/tmp/daemon.log",O_CREAT|O_WRONLY|O_APPEND,0600))<0){
perror("open");
exit(1);
}
write(fd,buf,len+1);
close(fd);
sleep(10);
}
return 0;
}
参考文章:
后台开发:核心技术与应用实践(徐晓鑫)