• 探究守护进程及其错误日志处理


    守护进程也是通常所说的deamon进程,他是linux中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性的执行某种任务,或者等待处理某些发生的事件

    编写守护进程的步骤:

    1.创建子进程,父进程退出。

    这儿有一个问题,由于父进程先于子进程退出,会造成子进程没有父进程,从而变成一个孤儿进程,在linux中,每当系统发现一个孤儿进程,就会自动由1号进程(init进程)收养,这样原来的子进程就变成init进程的子进程了

    其实现代码如下:

    pid=fork();

    if(pid>0)

    {

    exit(0);//父进程退出

    }

    2.在子进程中创建新会话

    这儿有一个进程组与会话期的概念

    进程组:一个或多个进程的集合,进程组由进程组id来唯一标识

    会话期:会话期是一个或多个进程组的集合,会话期的第一个进程称为会话组长

    函数setsid()用于创建一个新的会话,并担任会话组组长,其功能如下

    1.让进程摆脱原会话的控制

    2.让进程摆脱原进程组的控制

    3.让进程拜托原控制终端的控制

    pid_t setsid(void)

    成功返回改进程组id,失败返回-1;

    3.改变当当前工作目录chdir();

    由于使用fork创建的子进程继承了父进程的当前工作目录,由于在进程运行过程中,当前目录所在的文件系统是不能卸载的,这对以后使用造成了诸多麻烦,通常的做法是让“/”作为当前守护进程的当前工作目录

    4.重设文件权限掩码umask(0)

    把文件权限设置为0,可以增强该守护进程的灵活性

    5.关闭文件描述符

    同文件掩码一样,用fork函数新建的子进程会从父进程那里继承一些打开的文件,这些被打开的文件可能永远不会被守护进程访问,但一样占用资源,而且还可能导致所在的文件系统无法卸载

    int num;

    num=getdtablesize();//获取当前进程文件描述符大小

    for(int i=0;i<num;i++)

    {

    close(i);

    }

    实例如下:

    void deamon_mode(FILE *fp)
    {
      pid_t pid;

      pid = fork();
      if(pid < 0){
        perror("Fail to fork");
        exit(EXIT_FAILURE);
      }

      if(pid > 0){
        exit(EXIT_SUCCESS);
      }

      //创建新会话
      if(setsid() < 0){
        perror("Fail to fork");
        exit(EXIT_FAILURE);
      }

    //重设文件掩码
    umask(0);

    //改变进程的工作目录
    chdir("/");

    //关闭不需要的文件描述符
    close(0);
    close(1);
    close(2);

    //重定向
    dup2(fp->_fileno,0);
    dup2(fp->_fileno,1);
    dup2(fp->_fileno,2);

    return;
    }

    //a.out 0(非守护进程) log.txt
    //a..out 1(守护进程 ) log.txt
    int main(int argc, const char *argv[])
    {
      int fd;
      FILE *log_fp;
      int mode;

      if(argc < 3){
        fprintf(stderr,"Usage : %s < mode > <log file> ! ",argv[0]);
        exit(EXIT_FAILURE);
      }

      mode = atoi(argv[1]);
      if(mode){
        log_fp = fopen(argv[2],"a");
        if(log_fp == NULL){
        fprintf(stderr,"Fail to open %s : %s! ",argv[2],strerror(errno));
        exit(EXIT_FAILURE);
      }
      deamon_mode(log_fp);
    }else{
      log_fp = stderr;
    }

    fd = open("test",O_WRONLY | O_TRUNC | O_CREAT,0666);
    if(fd < 0){
      fprintf(log_fp,"Fail to open %s : %s! ","test",strerror(errno));
      exit(EXIT_FAILURE);
    }

      fprintf(log_fp,"open success! ");
      fflush(log_fp);

      while(1)
      ;

      return 0;
    }

    以上主要实现一个打印日志的一个功能,如果是守护进程则,通过守护进程打印日志到log.txt,否则非守护进程,打印到屏幕

    可能这儿有一个重定向dup2

    
    

    首先看看man手册

    
    
    dup 和 dup2 都可以用来复制一个现存的文件描述符。经常用来重新定向进程的 STDIN, STDOUT, STDERR。
    int dup ( int filedes ) ; 
    函数返回一个新的描述符,这个新的描述符是传给它的描述符的拷贝,若出错则返回 -1。由dup返回的新文件描述符一定是当前可用文件描述符中的最小数值。这函数返回的新文件描述符与参数 filedes 共享同一个文件数据结构。
    

    int dup2( int filedes, int filedes2 ) 同样,函数返回一个新的文件描述符,若出错则返回 -1。与 dup 不同的是,dup2 可以用 filedes2 参数指定新描述符的数值。如果 filedes2 已经打开,则先将其关闭。如若 filedes 等于 filedes2 , 则 dup2 返回 filedes2 , 而不关闭它。同样,返回的新文件描述符与参数 filedes 共享同一个文件数据结构。
    
    

    int main(int argc, const char *argv[])
    {
      FILE *fp;

    
    

      fp = fopen(argv[1],"a");

    
    

      close(0);
      close(1);
      close(2);

    
    

    #if 1
      dup2(fp->_fileno,0);
      dup2(fp->_fileno,1);
      dup2(fp->_fileno,2);
    #endif

    
    

    printf("default hello ! ");
    fprintf(stdout,"stdout hello ! ");
    fprintf(stderr,"stderr hello ! ");
    fflush(stdout);
    while(1)
    ;
    return 0;
    }

    编译并运行 a.out log.txt

    查看 cat log.txt

    可见本应该输出到控制终端的输出到了log.txt

    其实对应的日志处理还有几个比较常用:

    openlog/syslog/closelog,比较简单,查阅一下便知道!

  • 相关阅读:
    Rust 变量
    Rust-lang(hello world 续)
    Rust-lang(hello world)
    Java 1.8 ASM ClassReader failed to parse class file
    Sqoop使用笔记
    Jstorm
    从flume到kafka,日志收集
    vim-3-插件管理
    vim-2-使用进阶
    Git-Repo-Gerrit-1-Git介绍,安装和配置
  • 原文地址:https://www.cnblogs.com/bwbfight/p/9282911.html
Copyright © 2020-2023  润新知