守护进程(Daemon)是运行在后台、独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件的一种特殊进程。守护进程常常在系统引导装入时启动,在系统关闭时终止。Linux的大多数服务器就是用守护进程实现的。比如,Internet服务器inetd,Web服务器httpd等。同时,守护进程完成许多系统任务。比如,作业规划进程crond等。守护进程的创建本身并不复杂,复杂的是各种版本的Unix的实现机制不尽相同,造成不同Unix环境下守护进程的编程规则并不一致。
#include <unistd.h>
int daemon(int nochdir, int noclose);
nochdir为0则改变进程的当前工作目录到根目录
noclose为0则将标准输入、标准输出、标准错误重定向到/dev/null设备
成功返回0,错误返回-1,设置errno。
A、守护进程运行在后台
B、守护进程必须与当前运行环境隔离,运行环境包括未关闭的文件描述符、控制终端、会话和进程组、工作目录以及文件创建掩码等,运行环境是守护进程在创建时从父进程继承的。
进程属于一个进程组,进程组号(GID)就是进程组长的进程号(PID)。登录会话可以包含多个进程组。
Linux系统守护进程的创建流程:
为避免挂起控制终端将Daemon放入后台执行,让进程在后台运行的方法是在进程中调用fork使父进程终止,让Daemon在子进程中后台执行。
if(pid=fork())
exit(0); //是父进程,结束父进程,子进程继续
2、脱离控制终端、登录会话和进程组
setsid();
控制终端,登录会话和进程组通常是从父进程继承下来的,守护进程需要与从父进程继承下来的运行环境隔离。setsid()调用成功后,进程会成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。
3、禁止进程重新打开控制终端
进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端。
if(pid=fork()) exit(0);
创建第二子进程,结束第一子进程
4、改变当前工作目录
进程活动时,其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录,写运行日志的进程将工作目录改变到特定目录如/tmp。
chdir("/");
5、关闭打开的文件描述符
进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。
for(i=0;i< NOFILE;++i)//关闭打开的文件描述符
close(i);
6、设置文件创建掩码
进程从父进程继承了文件创建掩码,文件创建掩码可能会修改守护进程所创建的文件权限,所以需要将文件创建掩码清除。
umask(0);
7、处理SIGCHLD信号
在守护进程的创建中,处理SIGCHLD信号不是必须的,但对于那些创建子进程的守护进程来说,如果守护进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果守护进程等待子进程结束,将增加守护进程的负担,影响服务器进程的并发性能。在Linux下可以简单地将 SIGCHLD信号的操作设为SIG_IGN。
signal(SIGCHLD,SIG_IGN);
编写一个日志守护进程,每隔一定时间写入日志信息。
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <stdlib.h> #include <time.h> #include <signal.h> #define FILEMAX 65536 void daemon_init(void) { int pid; int i; if(pid = fork()) exit(0); else if(pid < 0) exit(-1); setsid(); if(pid = fork()) exit(0); else if(pid < 0) exit(-1); for(i = 0; i < FILEMAX; i++) close(i); chdir("/tmp"); umask(0); return ; } int main(int argc, char **argv) { FILE *fp; time_t t; signal(SIGCHLD, SIG_IGN); daemon_init(); while(1) { sleep(5); if((fp=fopen("test.log","a")) >=0) { t=time(0); fprintf(fp,"It is test at %s",asctime(localtime(&t)) ); fclose(fp);} } return 0; }
参考博文:
linux 守护进程编写 (CSDN zg_hover)
本文出自 “生命不息,奋斗不止” 博客,转载请与作者联系!
原文地址:http://9291927.blog.51cto.com/9281927/1811705