• 《APUE》读书笔记第十三章-守护进程


    守护进程

        守护进程是生存期较长的一种进程,它们常常在系统自举时启动,仅在系统关闭时才终止。因为它们没有控制终端,所以说它们是在后台运行的。UNIX系统由很多守护进程,它们执行日常事务活动.

         本章主要介绍守护进程的结构,以及如何编写守护进程程序和守护进程如何报告错误情况.

    一.守护进程的编程规则

       (1)首先要做的是调用umask将文件模式创建屏蔽字设置为0.这是由于继承得来的文件模式创建屏蔽字可能会拒绝设置某些权限。

       (2)调用fork,然后使父进程退出(exit).

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

       (4)将当前工作目录更改为根目录。

       (4)关闭不需要的文件描述符.这使守护进程不再持有从其父进程继承得来的某些文件描述符

       (5)某些守护进程打开/dev/null使其具有文件描述符0、1和2,这样任何一个试图读标准输入、写标准输出或标准出错的库例程都不会产生任何效果.

    #include <unistd.h>
    #include <syslog.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <sys/resource.h>
    void daemonize(const char* cmd){ int i,fd0,fd1,fd2; pid_t pid; struct rlimit r1; struct sigaction sa; umask(0); if(getrlimit(RLIMIT_NOFILE,&r1)<0){ printf("%s: can't get file limit",cmd); exit(-1); } if((pid=fork())<0){ printf("%s:can't fork",cmd); exit(-1); } else if(pid!=0){ //parent exit(0); } setsid(); /* ensure a session leader to lose controlling TTY. */ sa.sa_handler=SIG_IGN; sigemptyset(&sa.sa_mask); sa.sa_flags=0; if(sigaction(SIGHUP,&sa,NULL)<0){ printf("%s:can't ignore SIGHUP"); exit(-1); } if((pid=fork())<0){ printf("%s:can't ignore SIGHUP"); exit(-1); } else if(pid!=0) exit(0); if(chdir("/")<0){ printf("can't change directory to/"); exit(-1); } if(r1.rlim_max==RLIM_INFINITY){ r1.rlim_max=1024; } for(i=0;i<r1.rlim_max;i++) close(i); fd0=open("/dev/null",O_RDWR); fd1=dup(0); fd2=dup(0); openlog(cmd,LOG_CONS,LOG_DAEMON); if(fd0!=0 || fd1!=1 || fd2!=2){ syslog(LOG_ERR,"unexpected file description %d %d %d",fd0,fd1,fd2); exit(1); } }

    二.出错记录

    有三种方法产生日志消息:

    (1)内核例程可以调用log函数。任何一个用户进程用过open(打开)然后读(read)/dev/klog设备就可以读取这些消息。

    (2)大多数守护进程调用syslog函数以产生日志消息.

    (3)在此主机上的一个用户进程,或通过调用TCP/IP网络连接到此主机的其他主机上的一个用户进程可将日志消息发向UDP端口514.

    #include <syslog.h>
    
    void openlog(const char* ident,int option,int facility);
    void syslog(int priority,const char* format,...);
    void closelog(void);
    int setlogmask(int maskpri);
       //返回值:前日志记录优先级屏蔽值

    三.单实例守护进程

       为了正常运作,某些守护进程实现为单实例的,也就是任一时刻只运行该守护进程的一个副本。文件锁和记录锁是一种方法的基础,该方法用来保证一个守护进程只有一个副本在运行,它们提供了一种互斥机制。如果守护进程在整个文件上得到一把写锁,那么在该守护进程终止时,这把锁将被自动删除.

    •  若守护进程使用锁文件,那么该文件通常存放在/var/run目录中。锁文件的名字通常是name.pid,其中,name是该守护进程或服务的名字.例如,cron守护进程锁文件的名是/var/run/crond.pid.
    •  若守护进程支持配置选项,那么配置文件通常存放在/etc目录中,配置文件的名字通常是name.conf,其中,name是守护进程或服务的名字.
    • 守护进程可以用命令行启动,当通常是由系统初始化脚本之一(/etc/rc*或/etc/init.d/*)启动的.
     
    #include <unistd.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <string.h>
    #include <errno.h>
    #include <stdio.h>
    #include <sys/stat.h>
    
    sigset_t mask;
    extern int already_running(void);
    
    void reread(void){
         /..../
    }
    
    void* thr_fn(void* arg){
        int err,signo;
        
        for(;;){
            err=sigwait(&mask,&signo);
            if(err!=0){
                syslog(LOG_ERR,"sigwait failed");
                exit(1);
            }
            
            switch(signo){
                case SIGHUP:
                    syslog(LOG_INFO,"Re-reading configuration file!");
                    reread();
                    break;
                    
                case SIGTERM:
                    syslog(LOG_INFO,"got SIGTERM exiting");
                    exit(0);
                    
                default:
                     syslog(LOG_INFO,"unexpected signal %d
    ",signo);
            }
        }
        return (0);
    }
    
    
    int main(int argc,char* argv[]){
        int err;
        pthread_t tid;
        char *cmd;
        struct sigaction sa;
        
        if((cmd=strchr(argv[0],'/'))==NULL){
            cmd=argv[0];
        }
        else cmd++;
            
        /*
        *Become a daemon
        */
        daemonize(cmd);
        
        if(already_running()){
            syslog(LOG_ERR,"daemon already running");
            exit(1);
        }
        
        sa.sa_handler=SIG_DFL;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags=0;
        
        if(sigaction(SIGHUP,&sa,NULL)<0){
            err_printf("%s: can't restore SIGHUP default");    
        }
        
        sigfillset(&mask);
        if((err=pthread_sigmask(SIG_BLOCK,&mask,NULL))!=0)
             err_exit(err,"SIG_BLOCK error");
        
        err=pthread_create(&tid,NULL,thr_fn,0);
        if(err!=0){
            err_exit(err,"can't create thread");
        }
        
        exit(0);
        
    }
  • 相关阅读:
    jsoup 1.4.1 发布,超棒的 HTML 解析器
    NetBeans 时事通讯(刊号 # 126 Nov 24, 2010)
    利用cx_Freeze将py文件打包成exe文件(图文全解) 老爸的蒸面条 51CTO技术博客
    Newstyle Signal and Slot Support¶
    Python 标准库 urllib2 的使用细节
    cxfreeze package pyqt4 app with no backend terimal display
    Qt Widget Gallery
    Python32使用cxFreeze打包
    D3.js DataDriven Documents
    QT 的信号与槽机制介绍
  • 原文地址:https://www.cnblogs.com/sixue/p/4154408.html
Copyright © 2020-2023  润新知