#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>
#define MAXFILE 256
#define SERVER "/var/log/messages"
int main(void){
pid_t pc,p2;
int i, fd, len, len2;
char *daemon="daemon is writing\n";
char *child2="child2 is writing\n";
len = strlen(daemon);
len2 = strlen(child2);
//建立守护进程
pc = fork();
if(pc < 0){
printf("error fork\n");
exit(1);
}
// 关闭父进程
else if(pc > 0)
exit(0);
//建立新会话
setsid();
//更改目录为根目录
chdir("/");
//重设文件权限掩码
umask(0);
//关闭文件描述符号
for(i = 0; i < MAXFILE; i++)
close(i);
//打开文件
if((fd = open(SERVER, O_CREAT|O_WRONLY|O_APPEND, 0600)) < 0){
printf("open file error.\n");
exit(1);
}
//在守护进程中创建子进程
p2 = fork();
if(p2 < 0){
printf("error fork\n");
exit(1);
}
// 守护进程
else if(p2 > 0){
//等待子进程退出
waitpid(p2, NULL,0);
write(fd, daemon, len);
while(1)
sleep(10);
}
else{
write(fd, child2, len2);
sleep(10);
exit(0);
}
close(fd);
return 0;
}
ps:这里需要注意的是
- 在创建子进程的先把父进程退出,使得子进程沦为孤儿进程 ,在Linux系统中init进程会收留孤儿进程。所以原先的子进程会变成init进程的子进程
- 使用 fork 函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间,包括进程上下文、进程堆栈、内存信息、打开的文件描述符、信号控制设定、进程优先级、进程组号(会话组)、当前工作目录、根目录、资源限制、控制终端等,而子进程所独有的只有它的进程号、资源使用和计时器等
所以在创建守护进程的时候需要为子进程创建新会话,重设文件权限掩码,关闭文件描述符
在建立新会话后,守护进程就已经和所属的控制终端失去了联系,因此守护进程中用常规方法(如 printf)输出的字符也不可能在终端上显示出来。所以守护进程的文件描述符失去了存在的价值,应该被关闭,不然会消耗系统资源