原文链接:daemon函数详解原文链接
头文件与函数原型
#include <unistd.h>
int daemon(int nochdir,int noclose)
创建守护进程前提条件
- 将进程的工作目录修改为"/"根目录。daemon的参数nochdir为0时,即可将工作目录修改为根目录;
- 将标准输入,输出和错误输出重定向到/dev/null daemon的参数noclose为0时,输入,输出以及错误输出重定向到/dev/null 。
返回值:成功返回0 错误返回1
deamon()函数解析
#include <unistd.h>
int main(int argc,char *argv[])
{
if (daemon(0, 0)) {//调用glibc库函数daemon,创建daemon守护进程
perror("daemon");
return -1;
}
子进程内容
}
int daemon( int nochdir, int noclose )
{
pid_t pid;
if ( !nochdir && chdir("/") != 0 ) //如果nochdir=0,那么改变到"/"根目录
return -1;
if ( !noclose ) //如果没有noclose=0,那么开始输入,输出以及错误输出重定向到/dev/null
{
int fd = open("/dev/null", O_RDWR);//打开神奇的黑洞文件.
if ( fd < 0 )
return -1;
//每个进程都拥有自己fds文件描述符表,
//fdt->fd[0],fdt->fd[1],fdt->fd[2],
//表中fd[0],fd[1],和fd[2]文件句柄位置对应的fops文件操作函数集,分别与标准输入,标准输出,标准错误输出相关联
//所以用户应用程序调用open函数打开文件时,默认都是以3索引为开始句柄,也就是fd[3],故当前open返回的文件句柄最小值为3
//dup2(unsigned int oldfd, unsigned int newfd)系统调用就是用oldfd的fops操作文件集file,复制到newfd所在处
//即:fdt->fd[newfd] = fdt->fd[oldfd];
if ( dup2( fd, 0 ) < 0 || //使用字符设备/dev/null的fops函数操作集,替换0句柄对应的文件操作集.
dup2( fd, 1 ) < 0 || //使用字符设备/dev/null的fops函数操作集,替换1句柄对应的文件操作集.
dup2( fd, 2 ) < 0 ) //使用字符设备/dev/null的fops函数操作集,替换2句柄对应的文件操作集.
{
close(fd);
return -1;
}
//如果替换成功,那么键盘的任何操作将不会对该进程产生任何影响,因为0,1,2句柄所在处的fops文件操作集已经都变成了,
//被重定向为"/dev/null"空洞设备的fops.所以对0,1,2句柄的读写操作,也就是在对/dev/null设备作读写操作.
close(fd); //关闭打开的/dev/null
}
pid = fork();//创建子进程.
if (pid < 0)
return -1;
if (pid > 0)
_exit(0); //返回执行的是父进程,那么父进程退出,让子进程变成真正的孤儿进程.
//ok,我们期望的daemon子进程执行到这里了.
if ( setsid() < 0 ) //设置session id.
return -1;
return 0; //成功创建daemon子进程[luther.gliethttp].
}