#include#define ERR_EXIT(m)
do {
perror(m);
exit(EXIT_FAILURE);
} while(0)
int setup_daemon(int, int);
/* 守护进程一直在后台运行且无控制终端 */
int main(int argc, char *argv[])
{
// daemon(0, 0)
setup_daemon(0, 0);
printf("test ...
"); // 无输出
for(;;) ;
return 0;
}
int setup_daemon(int nochdir, int noclose)
{
pid_t pid;
pid = fork();
if (pid == -1)
ERR_EXIT("fork error");
if (pid > 0)
exit(EXIT_SUCCESS);
/* 调用setsid的进程不能为进程组组长,故fork之后将父进程退出 */
setsid(); // 子进程调用后生成一个新的会话期
if (nochdir == 0)
chdir("/"); //更改当前目录为根目录
if (noclose == 0)
{
int i;
for (i = 0; i
close(i);
open("/dev/null", O_RDWR); // 将标准输入,标准输出等都重定向到/dev/null
dup(0);
dup(0);
}
return 0;
}
执行程序再ps axj 一下:
simba@ubuntu:~/Documents/code/linux_programming/APUE/process$ ./daemon
simba@ubuntu:~/Documents/code/linux_programming/APUE/process$ ps axj
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
...........................................................................................................................
1 7678 7678 7678 ? -1 Rs 1000 0:03 ./daemon
可以看出守护进程的ID也是进程组的ID,也是会话期的ID,此外这个会话期没有前台进程组。
五、使用daemon函数实现守护进程
功能:创建一个守护进程
原型:int daemon(int nochdir, int noclose);
参数:
nochdir:=0将当前目录更改至“/”
noclose:=0将标准输入、标准输出、标准错误重定向至“/dev/null”
注:也有一些说法,表示daemon 实现是fork 2 次,具体可以google fork 2 times daemon,据说主要是为了避免子进程的僵尸进程问题。
C++ Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
int daemon()
{
int fd;
pid_t pid;
if((pid = fork()) != 0)
{
exit(0);
}
setsid();
signal(SIGINT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
signal(SIGCHLD, SIG_IGN);
signal(SIGTERM, SIG_IGN);
struct sigaction sig;
sig.sa_handler = SIG_IGN;
sig.sa_flags = 0;
sigemptyset(&sig.sa_mask);
sigaction(SIGPIPE,&sig,NULL);
umask(0);
if((pid = fork()) != 0)
{
exit(0);
}
fd = open("/dev/null", O_RDWR);
dup2(fd, STDIN_FILENO)
dup2(fd, STDOUT_FILENO)
return 0;
}
参考:《linux c 编程一站式学习》、《APUE》