守护进程(daemon)是指在后台运行的,没有控制终端与之相连的进程。它独立于控制终端,通常周期性的执行某种任务。
守护进程是一种很有用的进程。Linux的大多数服务器就是用守护进程的方式实现的,如Internet服务器进程inetd,Web服务器进程http等。守护进程在后台
运行,类似于windows中的系统服务。
守护进程的启动方式:
1、系统启动时从启动脚本/etc/rc.d中启动
2、作业规划进程crond启动
3、用户终端(shell)执行
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
创建守护进程的步骤:
1、fork产生一个子进程,让父进程退出
2、调用setsid创建一个新会话。控制终端,登陆会话和进程组通常是从父进程继承下来的。
守护进程要摆脱他们,不受他们的影响,其方法是调用setsid使进程成为一个会话组长
注意:当进程是会话组长时,调用setsid会失败,当时第一点保证了进程不是会话组长。setsid调用成功后,进程成为新的会话组长和进程组长,
并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性,进程同时与控制终端脱离。
3、禁止进程重新打开控制终端。以上步骤,进程已经成为一个无终端的会话组长,但是他可以重新申请打开一个终端。为了避免这种情况的发生,可以通过使进程不再是会话
组长来实现。再一次通过fork创建一个新的子进程,使调用fork的进程退出。
4、关闭不在需要的文件描述符。创建的子进程从父进程继承打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及无法预料的错误。
先得到最高的文件描述符,然后用一个循环过程,关闭0到最高文件描述符值的所有文件描述符。
5、将当前目录更改为根目录,当守护进程当前工作目录在一个装配文件系统时,该文件系统不能被拆卸。一般需要将工作目录改为根目录。
6、将文件创建时使用的屏蔽字设置为0,进程从创建他的父进程那里继承的文件创建屏蔽字可能会拒绝某些许可权。为防止这一点,使用umask(0)将屏蔽字清零。
7、处理SIGCHLD信号。这一步不是必须的。但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束,子进程将会成为僵尸进程,从而占用系统资源。如果父进程等待子进程结束,
将增加父进程的负担,影响服务器进程的并发性。在Linux下可以简单地将SIGCHLD信号的操作设为SIG_IGN。这样,子进程结束时不会产生僵尸进程。
#include <time.h> #include <syslog.h> #include <unistd.h> #include <signal.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/param.h> int init_daemon() { int pid; int i; /*忽略终端I/O信号,STOP信号*/ signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGHUP, SIG_IGN); /创建子进程/ pid = fork(); if(pid > 0) { //父进程退出,使得子进程成为后台进程 exit(0); } else if(pid < 0) { return -1; } //建立一个新的进程组,在这个新的进程组中,子进程成为这个进程组的首进程,以使该进程脱离所有终端 setsid(); //再次新建一个子进程,退出父进程,保证该进程不是进程组长,同时让该进程无法再打开一个新的终端 pid = fork(); if(pid > 0) { exit(0); } else if(pid < 0) { return -1; } //关闭所有从父进程继承的不再需要的文件描述符 for(i=0;i<NOFILE;close(i++)); //改变工作目录,使得进程不与任何文件系统联系 chdir("/"); //将文件屏蔽字设置为0 umask(0); //忽略SIGCHLD信号 signal(SIGCHLD, SIG_IGN); return 0; } int main() { time_t now; init_daemon(); syslog(LOG_USER|LOG_INFO, "test daemon "); while(1) { sleep(8); time(&now); syslog(LOG_USER|LOG_INFO, "system time: %s", ctime(&now)); } }
系统ubuntu
注意使用syslog之前,需要先进行配置修改文件 /etc/rsyslog.d/50-default.conf
放开 user.* -/var/log/user.log 这行的注释。
重新启动rsyslog服务 切换到目录/etc/init.d
执行:
/etc/init.d# ./rsyslog stop
/etc/init.d# ./rsyslog start
关于syslog的配置:
http://blog.csdn.net/shi1122/article/details/8626629