《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\n",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);

}
时间: 2024-10-08 10:08:57

《APUE》读书笔记第十三章-守护进程的相关文章

《Unix环境高级编程》读书笔记 第13章-守护进程

1. 引言 守护进程是生存期长的一种进程.它们常常在系统引导装入时启动,仅在系统关闭时才终止.它们没有控制终端,在后台运行. 本章说明守护进程结构.如何编写守护进程程序.守护进程如何报告出错情况. 2. 守护进程的特征 基于BSD的系统下执行:ps -axj -a 显示由其他用户所拥有的进程的状态:-x 显示没有控制终端的进程状态:-j 显示与作业有关的信息 基于System V的系统下执行:ps -efj Linux下执行以上两个命令输出一致 常见的守护进程: kswapd,内存换页守护进程.

Java编程思想第四版读书笔记——第十三章 字符串

Java编程思想第四版读书笔记--第十三章 字符串 字符串的操作是计算机程序设计中最常见的行为. 关键词: StringBuilder ,StringBuffer,toString(),format转换,正则表达式, 1.不可变String String对象时不可变的.每当把String对象作为方法的参数时,都会复制一份引用.(其实就是对函数中参数列表中参数的操作不会影响外面的原参数) 如下: import static net.mindview.util.Print.*; public cla

apue学习笔记(第十三章 守护进程)

本章将说明守护进程结构,以及如何编写守护进程程序. 守护进程,也就是通常说的Daemon进程,是Unix中的后台服务进程.它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件. 编程规则 在编写守护进程程序时需遵循一些基本规则,以防止产生不必要的交互作用.下面将说明这些规则. 1.调用umask将文件模式创建屏蔽字设置为一个已知值(通常是0) 2.调用fork,然后使父进程exit,保证了子进程不是进程组的组长进程,是下面进行setsid调用的先决条件 3

《C++ Primer》读书笔记—第十三章 控制拷贝

声明: 文中内容收集整理自<C++ Primer 中文版 (第5版)>,版权归原书所有. 学习一门程序设计语言最好的方法就是练习编程 第III部分,类设计者的工具 1.类是C++的核心概念.每个类都定义了一个新类型和在此类型对象上可执行的操作. 2.当定义一个类时,我们显式或隐式地指定在此类型的对象的拷贝.移动.赋值和销毁时做什么.一个类通过定义五种特殊的成员函数来控制这些操作,包括:拷贝构造函数(copy construcor),拷贝赋值运算符(copy-assignment operato

APUE读书笔记-第四章 文件和目录

到第四章了,不知什么时候才能把这本书看完,耽误的时间太多了. 第四章是在第三章的基础上,主要描述文件系统的其他性质和文件的性质. 4.2 stat.fstat.fstatat.lstat函数 首先来看看这四个函数的原型: #include <sys/stat.h> ///usr/include/x86_64-linux-gnu/sys/ int stat (const char *__restrict __file, struct stat *__restrict __buf) int fst

apue读书笔记-第14章 高级IO

多路I/O转接 与select函数不同,poll不是为每个状态(可读性.可写性和异常状态)构造一个描述符集,而是构造一个pollfd结构数组,每个数组元素指定一个描述符编号以及其所关心的状态 readv和writev函数 作用:在一次函数调用中读.写多个非连续缓存区 总结:应当用尽量少的系统调用次数来完成任务.如果只写少量的数据,会发现自己复制数据然后使用一次write会比用writev更合算.但也可能发现,这样获得的性能提升并不值得,因为管理中间缓冲区会增加程序复杂度. readn和write

APUE读书笔记-第三章 文件I/O

今天看得挺快的,一下子就把第二章看完了,不过第二章也确实看得不仔细,这一章其实在程序设计中还是非常重要的,因为这一章的内容决定了程序的可移植性. 好了,回到这一章的主题文件I/O. 3.2节主要对文件描述符的概念进行了简单的介绍.根据APUE:文件描述符是一个非负整数.当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符.我也简单地翻了一下LKD和<深入理解linux内核>,其中对于文件描述符的讲解不是很多,所以对于文件描述符也谈不出来太深入理解,各大家还是分享一篇blog吧.

APUE读书笔记-第六章 系统数据文件和信息

昨天看完了,今天来看看第六章.感觉第六章的内容不是非常重要.简单看看吧 6.2 口令文件 口令文件其实就是/etc文件夹下的passwd文件,但处于安全性的考虑,我们无法直接读取它.就是通过直接限制权限的方式对其进行保护,passwd文件具体权限如下: -rw-r--r-- 1 root root 可以看到只有root用户具有读写权限,与root同组的用户与其他用户仅具有读权限. 不过为了解决以上问题,Linux中给出了一系列数据结构与函数帮助我们操纵口令文件,首先是关键数据结构,定义位于/in

APUE读书笔记-第五章 标准I/O库

今天草草的把第四章结了,后面的内容分析的也不是很详细,就连书中的例子都没有怎么实验,还是等以后有机会吧. 从5.3节开始研究起吧,这一节主要谈了一个进程预定义的3个流,分别是标准输入.标准输出和标准错误,通过stdin.stdout.stderr引用.这里要和进程中的文件描述符STDIN_FILENO.STDOUT_FILENO.STDERR_FILENO相区分. /* Standard streams. */ extern struct _IO_FILE *stdin; /* Standard