守护进程

来源:互联网 发布:淘宝 知乎 姨 编辑:程序博客网 时间:2024/05/01 12:50

一、常用的守护进程简单介绍:

  • Keventd:为在内核中运行计划执行的函数提供进程上下文。
  • kapmd:高级电源管理。
  • kswapd:页面调出。(将脏页面以低速写到磁盘上从而使这些页面在需要时仍可回收使用)
  • bdflush:将脏缓冲区从缓存池中冲洗到磁盘上。
  • kupdated:每个一定时间间隔,这个守护进程将脏页面冲洗到磁盘上。
  • portmap:端口映射提供将RPC程序号映射为网络端口号。
  • syslogd:把系统消息记入日志。
  • inetd:监听网络接口,以便取得来自网络的对各种网络服务进程的请求。
  • cron:在指定的日期和时间执行指定的命令。

二、守护进程的编程规则

1. 重设文件创建掩模

进程从创建它的父进程那里继承了文件创建掩模。它可能修改守护进程所创建的文件的存取位。为防止这一点,将文件创建掩模清除:umask(0);

2.在后头运行

调用fork,然后使父进程终止。这样做的目的是:第一,如果该守护进程是作为一条简单shell命令启动的,那么父进程终止使得shell认为这条命令已经执行完毕,那么子进程就自动在后台运行了。第二,子进程继承了父进程的进程组ID,但具有一个新的进程ID,这就保证了进程不是一个进程组的组长进程。这是接下去调用setsid的必要条件。

3.脱离控制终端,登录会话和进程组

调用setsid以创建一个新会话。使调用进程:(a)成为新会话的首进程,(b)成为一个新进程组的组长进程,(c)没有控制终端。

有必要先介绍一下Linux中的进程与控制终端,登录会话和进程组之间的关系:进程属于一个进程组,进程组号(GID)就是进程组长的进程号(PID)。登录会话可以包含多个进程组。这些进程组共享一个控制终端。这个控制终端通常是创建进程的登录终端。

控制终端,登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们,使之不受它们的影响。方法是在第2点的基础上,调用setsid()使进程成为会话组长。

说明:当进程是会话组长时setsid()调用失败。但第二点已经保证进程不是会话组长。setsid() 调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性,进程同时与控制终端脱离。

4. 禁止进程重新打开控制终端

现在,进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端:

if(pid=fork())

exit(0);//结束第一子进程,第二子进程继续(第二子进程不再是会话组长)

5. 改变当前工作目录

进程活动时,其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录。

chdir("/");

6.关闭打开的文件描述符

进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。

7.将文件描述符0、1、2重定向到/dev/null



初始化一个守护进程的实例代码:
#include <stdlib.h>#include <stdio.h>#include <syslog.h>#include <signal.h>#include <fcntl.h>#include <sys/resource.h>#include <errno.h>#include <sys/stat.h>#include <string.h>#define LOCKDIR "/var/run/"#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)int daemonize(const char *cmd);int already_running(const char *cmd);int lockfile(int);int main(int argc ,char **argv){        FILE *f;        time_t t;        if(daemonize(argv[0]) < 0){                printf("daemonize error.\n");                exit(1);        }        /* make sure only one cope of the daemon is running */        if(already_running(argv[0])){                syslog(LOG_ERR,"daemon already running");                exit(1);        }        while(1){                sleep(60);                if((f = fopen("test.log","a")) >= 0){                        t=time(0);                        fprintf(f,"I'm here at %s\n",asctime(localtime(&t)));                }                fclose(f);        }        return 0;}int  daemonize(const char *cmd){        int i,fd0,fd1,fd2;        pid_t pid;        struct rlimit rl;        struct sigaction sa;        /* clear file creation mask  */        umask(0);        /* get maximum number of file descriptors */        if(getrlimit(RLIMIT_NOFILE, &rl) < 0 )                exit(1);        /* become a session leader to lose controlling tty */        if((pid = fork()) < 0)                return -1;        else if(pid != 0 )                exit(0);        setsid();        /*ensure future opens won't allocate controlling TTYs  */        sa.sa_handler=SIG_IGN;        sigemptyset(&sa.sa_mask);        sa.sa_flags=0;        if(sigaction(SIGHUP,&sa,NULL) < 0 )                return -1;        if((pid = fork()) < 0 )                return -1;        else if(pid != 0 )                exit(0);        /* change the current working directory to the root */        if(chdir("/") < 0 )                return -1;        /* close all open file descriptors */        if(rl.rlim_max == RLIM_INFINITY)                rl.rlim_max=1024;        for(i=0; i < rl.rlim_max; i++)                close(i);        /* attach file descriptors 0,1,2 to /dev/null */        fd0=open("/dev/null",O_RDONLY);        fd1=open("/dev/null",O_RDWR);        fd2=open("/dev/null",O_RDWR);        /* initialize the log file */        openlog(cmd, LOG_CONS, LOG_DAEMON);        if(fd0 != 0 ||fd1 != 1 ||fd2 != 2){                syslog(LOG_ERR,"unexpected file descriptors %d %d %d",fd0,fd1,fd2);                exit(1);        }        return 0;}int lockfile(int fd){        struct flock fl;        fl.l_type=F_WRLCK;        fl.l_start=0;        fl.l_whence=SEEK_SET;        fl.l_len=0;        return (fcntl(fd,F_SETLK,&fl));}int already_running(const char *cmd){        int fd;        char buf[16];        char lfile[32];        strcat(lfile,LOCKDIR);        strcat(lfile,cmd);        strcat(lfile,".pid");        if((fd = open(lfile, O_RDWR|O_CREAT, LOCKMODE)) < 0 ){                syslog(LOG_ERR, "can't open %s: %m",lfile);                exit(1);        }        if(lockfile(fd) < 0 ){                if(errno == EACCES || errno == EAGAIN){                        close(fd);                        return 1;                }                syslog(LOG_ERR, "can't lock %s: %m",lfile);                exit(1);        }        ftruncate(fd,0);        sprintf(buf, "%ld",(long)getpid());        write(fd,buf,strlen(buf)+1);        return 0;}