什么是守护进程?
守护进程就是通常所说的Daemon进程,它是Linux中的后台服务程序。它是一个生存期较长的进程,通常独立于终端并且周期性的执行某种需要的任务以及有时候会等待一些将会发生的事情。守护进程常常会在系统启动的时候开始执行,在系统关闭的时候关闭,它实现了linux系统中的很多系统级的服务。
另一方面Daemon不受终端的影响,不会因为某个终端的关闭而关闭,所以,如果你希望你的进程不会因为用户或者终端的变化而变化,那么你就必须要知道怎么把你的进程设置为守护进程(也就是所说的Daemon进程了)。
编写守护进程其实没有看似那么的复杂,就是完成以下五步骤即可创建出一个Daemon进程,
创建守护进程的5个步骤:
(1)创建子进程,父进程退出 。这一步就是要在外表看来让子进程与终端脱离。这个时候原先的子进程就会变为孤儿进程,那么孤儿进程就会被init进程进行收养了。
(2)
在子进程中创建的新会话setsid() : 调用者不能是组长进程],这一步是创建守护进程最重要的一步了,虽然实现非常大的简单,但是意义非常的重大。先介绍下setsid()函数的作用:
setsid()函数用于创建一个新的会话,并担任该会话组的组长,调用setsid()有下面3个作用:
(1)让进程拜托原会话的控制
(2)让进程拜托原进程组的控制
(3)让进程拜托原控制终端的控制
那么接下来我们就会很清楚的知道我们为什么要去执行setsid()函数了,因为在第一步我们创建进程的时候,子进程全盘复制了父进程的会话期,进程组,和控制终端等。虽然父进程退出了,但原先的会话期,进程组和控制终端没有变,因此还不是真正意义上的独立了,而setsid()函数能够让进程完全的独立出来,从而脱离所有其它进程的控制哦。
(3)改变进程的工作目录到"/" ; 改变工作目录的函数时chdir();
(4)重设文件掩码,通常使用的方法是 umask(0) ; 文件权限掩码(通常用8进制表示)的作用是屏蔽文件权限中的对应位。
(5)关闭不需要的文件描述符号 ,通常关闭的是[0,1,2,3]
同文件权限掩码一样,用fork()函数新建的子进程会从父进程那里继承一些已经打开了的文件。这些被打开的文件可能永远不会被守护进程访问,但它们一样占用系统资源,而且还可能导致所在的文件系统无法被卸载。特别是守护进程和终端无关,所以指向终端设备的标准输入,标准输出和标准错误流,已经失去了存在的价值,应当被关闭。通常的做法如下:
int num;
num = getdtablesize(); //获取当前进程文件描述符表的大小
for(i = 0;i < num ;i++)
{
close( i );
}
经过上述的五大步骤,一个简单的守护进程就建立起来了。
大致的流程见下图:
好了,大致的思想了解之后,接下来的事情就简单的多了,无非就是代码的实现的问题了;
下面以守护进程为出发点列举一个例子,希望可以详细的了解下,看看守护进程是如何实现时间日志的
#include <head.h>
#define daemo_mode 0
#define nomal_mode 1
int daemo() //5步创建守护进程
{
pid_t pid;
pid = fork();
if(pid < 0)
{
fprintf(stderr,"File to fork\n",strerror(errno));
exit(EXIT_FAILURE);
}
if(pid > 0)
exit(EXIT_FAILURE);
if(setsid() < 0)
{
perror("File to setsid");
exit(EXIT_FAILURE);
}
chdir("/");
umask(0);
close(0);
close(1);
close(2);
return 0;
}
int get_line(FILE *fp)
{
int line;
char *tmp;
char buf[4096];
while(1)
{
tmp = fgets(buf,sizeof(buf),fp);
if(tmp == NULL)
break;
if(buf[strlen(tmp) - 1] == '\n')
line++;
}
return line;
}
int do_nomal(const char *filename)
{
FILE * fp;
time_t t;
struct tm *ptm;
int line = 0;
fp = fopen(filename,"a+");
if(fp == NULL)
{
fprintf(stderr,"File to fopen\n",strerror(errno));
exit(EXIT_FAILURE);
}
line = get_line(fp);
while(1)
{
++line;
time(&t); //The realization of time
ptm = localtime(&t);
sleep(1);
fflush(fp);
fprintf(fp,"%d-%d-%d",(1900+ptm->tm_year),(1+ptm->tm_mon),ptm->tm_mday);
fprintf(fp,"%d:%d:%d\n",ptm->tm_hour,ptm->tm_min,ptm->tm_sec);
}
return 0;
}
// ./a.out log 0/1
int main(int argc, const char *argv[])
{
if(argc < 3)
{
fprintf(stderr,"Usage : %s argv[1] argv[2]\n",argv[0]);
exit(EXIT_FAILURE);
}
int mode = atoi(argv[2]);
switch(mode)
{
case daemo_mode:
daemo();
break;
case nomal_mode:
break;
default:
printf("Unknow mode \n");
goto next;
}
do_nomal(argv[1]);
next:
return 0;
}