守护进程也称精灵进程(daemon)是生存期较长的种进程。它们常常在系统自举时启动,仅在系统关闭时才终止。因为它们没有控制终端,所以说它们是在后台运行的。
运行周期长,后台运行,不需要和用户交互。
守护进程编程流程:
1、调用fork,然后使父进程退出(exit)。 这样做实现了下面几点:第一,如果该守护进程是作为一条简单shell命令启动的,那么父进程终止使得shell认为这条命令已经执行完毕:第二,子进程继承了父进程的进程组ID,但具有一个新的进程ID,这就保证了子进程不是一个进程组的组长进程,成为新的组员进程,可以成为新的组长进程。这对于下面就要做的setsid调用是必要的前提条件。
2、调用setsid以创建一个新会话。使调用进程:
(a)成为新会话首进程。(b) 成为一个新进程组的组长进程。(c) 没有控制终端。
3、调用fork,然后使父进程退出(exit)。******此步骤可有可无,保险起见
4、将当前工作目录更改为根目录,chdir("/")。从父进程处继承过来的当前工作目录可能在一个装配文件系统中。因为守护进程通常在系统再引导之前是一直存在的,所以如果守护进程的当前工作目录在一-个装配文件系统中,那么该文件系统就不能被拆卸。这与装配文件系统的原意不符。另外,某些守护进程可能会把当前工作目录更改到某个指定位置,在那里做它们的工作。例如,行式打印机假脱机守护进程常常将其工作目录更改到它们的spool目录上。
5、调用umask将文件模式创建屏蔽字设置为0,清除掩码。由继承得来的文件模式创建屏蔽字可能会拒绝设置某些权限。例如,若守护进程要创建一个组可读、写的文件,而继承的文件模式创建屏蔽字可能屏蔽了这两种权限,于是所要求的组可读、写就不能起作用。
6、close()关闭不再需要的文件描述符。这使守护进程不再持有从其父进程继承来的某些文件描述符(父进程可能是shell进程,或某个其他进程)。
7、处理其他情况的进程(僵死进程)。
具体实现一个简单的守护进程:
//实现守护进程在一个日志文件每五秒写入记录时间
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <time.h>
int main()
{
int pid = fork(); //fork,退出父进程
if( pid != 0)
{
exit(0);
}
setsid(); //创建新会话
pid = fork(); //让此进程失去会话首进程、组长进程的身份,变为组员(普通)进程;
if( pid != 0)
{
exit(0);
}
chdir("/"); //改变工作环境
umask(0); //清除掩码
int i = 0;
int maxfd = getdtablesize();//获取文件描述符大小,返回文件的最大数量进程可以打开的,比个文件描述符的最大可能值多个。
for(;i<maxfd;i++)
{
close(i); //关闭文件描述符
}
while(1)
{
FILE *fp = fopen("/tmp/guoweid.log","a");
if( fp == NULL)
{
exit(0);
}
time_t tv;
time(&tv); //获取1970.01.01到目前的秒数
//asctime 将时间日期以字符串格式表示
//localtime获取当前时间和日期并转换为本地时间
fprintf(fp,"Time is %s",asctime(localtime(&tv)));
fclose(fp);
sleep(5);
}
exit(0);
}
运行演示:
运行之后由于是在后台,所以在终端看不到。
查看到进程信息,如图所得示;下来转入/tmp目录下找到日志文件guoweid.log。使用命令 tail -f guoweid.log 动态查看日志文件打印,对比下面图片;