守护进程(daemon)也叫精灵进程,它是运行在后台的与终端无关的一种特殊进程
#include <unistd.h>
pid_t setsid(void);
setsid()函数调用时,要保证当前进程不是进程组组长,否则出错返回-1
可以调用fork()做到这一点,fork出来的子进程和当前进程属于同一个进程组,而一个进程组组长是该进程组的第一个进程,所以保证fork出来的子进程一定不是进程组组长,接着调用setsid()函数
setsid()函数调用成功后,当前进程独自成一个会话(sid为当前进程id),且为进程组组长(gid也为进程id),如果当前进程有控制终端,则它会失去这个终端
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void create_daemon()
{
pid_t id=-1;
struct sigaction sa;
sa.sa_handler=SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags=0;
if(sigaction(SIGCHLD,&sa,NULL)<0){//注册子进程退出忽略信号
return;
}
if((id=fork())<0){//保证当前进程不是组长进程,否则下面setdid会失败
perror("fork");
exit(-1);
}
else if(id!=0){//父进程退出
exit(0);
}
umask(0);
if(-1==setsid()){//当前进程成为了守护进程,和终端无关
perror("setsid");
exit(1);
}
if(-1==(id=fork())){//保证进程不会再次打开终端
perror("fork");
}
else if(0!=id){//父进程退出
exit(0);
}
if(-1==chdir("/")){//把当前守护进程的工作目录改为根目录
perror("chdir");
exit(-1);
}
close(0);//关闭不必要的文件描述符
int fd=-1;
fd=open("/dev/null",O_RDWR);
dup2(fd,1);
dup2(fd,2);
}
int main()
{
create_daemon();
while(1){
;
}
return 0;
}运行结果:
运行程序后用ps ajx | grep -E ‘my_daemon‘命令后有两个进程,其中第一行就是我们创建的守护进程
它的父进程为1号init进程,因为它的父进程退出后它成为了孤儿进程,被init进程收养
PGID和SID都为2816,而它的PID为2817,可看出它不是该会话的会话首进程,也不是它所属进程组的组长进程
TTY列是?说明该进程和终端无关
ps ajx | head -n1 命令可查看头部信息
本文出自 “零蛋蛋” 博客,请务必保留此出处http://lingdandan.blog.51cto.com/10697032/1772634
原文地址:http://lingdandan.blog.51cto.com/10697032/1772634