精华内容
下载资源
问答
  • linux守护进程

    2013-11-24 19:53:56
    Linux 守护进程的编程方法  守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。Linux的大多数服务器就是用守护...

    原文地址:

    http://blog.csdn.net/hairetz/article/details/4195036



    Linux 守护进程的编程方法 

    守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。Linux的大多数服务器就是用守护进程实现的。比如,Internet服务器inetd,Web服务器httpd等。同时,守护进程完成许多系统任务。比如,作业规划进程crond,打印进程lpd等。 
    守护进程的编程本身并不复杂,复杂的是各种版本的Unix的实现机制不尽相同,造成不同Unix环境下守护进程的编程规则并不一致。这需要读者注意,照搬某些书上的规则(特别是BSD4.3和低版本的System V)到Linux会出现错误的。下面将全面介绍Linux下守护进程的编程要点并给出详细实例。 
    一. 守护进程及其特性 
    守护进程最重要的特性是后台运行。在这一点上DOS下的常驻内存程序TSR与之相似。其次,守护进程必须与其运行前的环境隔离开来。这些环境包括未关闭的文件描述符,控制终端,会话和进程组,工作目录以及文件创建掩模等。这些环境通常是守护进程从执行它的父进程(特别是shell)中继承下来的。最后,守护进程的启动方式有其特殊之处。它可以在Linux系统启动时从启动脚本/etc/rc.d中启动,可以由作业规划进程crond启动,还可以由用户终端(通常是shell)执行。 
    总之,除开这些特殊性以外,守护进程与普通进程基本上没有什么区别。因此,编写守护进程实际上是把一个普通进程按照上述的守护进程的特性改造成为守护进程。如果读者对进程有比较深入的认识就更容易理解和编程了。 
    二. 守护进程的编程要点 
    前面讲过,不同Unix环境下守护进程的编程规则并不一致。所幸的是守护进程的编程原则其实都一样,区别在于具体的实现细节不同。这个原则就是要满足守护进程的特性。同时,Linux是基于Syetem V的SVR4并遵循Posix标准,实现起来与BSD4相比更方便。编程要点如下; 
    1. 在后台运行。 
    为避免挂起控制终端将Daemon放入后台执行。方法是在进程中调用fork使父进程终止,让Daemon在子进程中后台执行。 
    if(pid=fork()) 
    exit(0);//是父进程,结束父进程,子进程继续 
    2. 脱离控制终端,登录会话和进程组 
    有必要先介绍一下Linux中的进程与控制终端,登录会话和进程组之间的关系:进程属于一个进程组,进程组号(GID)就是进程组长的进程号(PID)。登录会话可以包含多个进程组。这些进程组共享一个控制终端。这个控制终端通常是创建进程的登录终端。 
    控制终端,登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们,使之不受它们的影响。方法是在第1点的基础上,调用setsid()使进程成为会话组长: 
    setsid(); 
    说明:当进程是会话组长时setsid()调用失败。但第一点已经保证进程不是会话组长。setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性,进程同时与控制终端脱离。 
    3. 禁止进程重新打开控制终端 
    现在,进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端: 

    if(pid=fork()) 
    exit(0);//结束第一子进程,第二子进程继续(第二子进程不再是会话组长) 
    4. 关闭打开的文件描述符 
    进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。按如下方法关闭它们: 
    for(i=0;i 关闭打开的文件描述符close(i);> 
    5. 改变当前工作目录 
    进程活动时,其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录。对于需要转储核心,写运行日志的进程将工作目录改变到特定目录如/tmpchdir("/") 
    6. 重设文件创建掩模 
    进程从创建它的父进程那里继承了文件创建掩模。它可能修改守护进程所创建的文件的存取位。为防止这一点,将文件创建掩模清除:umask(0); 
    7. 处理SIGCHLD信号 
    处理SIGCHLD信号并不是必须的。但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在Linux下可以简单地将SIGCHLD信号的操作设为SIG_IGN。 
    signal(SIGCHLD,SIG_IGN); 
    这样,内核在子进程结束时不会产生僵尸进程。这一点与BSD4不同,BSD4下必须显式等待子进程结束才能释放僵尸进程。 
    三. 守护进程实例 
    守护进程实例包括两部分:主程序test.c和初始化程序init.c。主程序每隔一分钟向/tmp目录中的日志test.log报告运行状态。初始化程序中的init_daemon函数负责生成守护进程。读者可以利用init_daemon函数生成自己的守护进程。 
    1. init.c清单 

    #include < unistd.h > 
    #include < signal.h > 
    #include < sys/param.h > 
    #include < sys/types.h > 
    #include < sys/stat.h > 
    void init_daemon(void) 

    int pid; 
    int i; 
    if(pid=fork()) 
    exit(0);//是父进程,结束父进程 
    else if(pid< 0) 
    exit(1);//fork失败,退出 
    //是第一子进程,后台继续执行 
    setsid();//第一子进程成为新的会话组长和进程组长 
    //并与控制终端分离 
    if(pid=fork()) 
    exit(0);//是第一子进程,结束第一子进程 
    else if(pid< 0) 
    exit(1);//fork失败,退出 
    //是第二子进程,继续 
    //第二子进程不再是会话组长 

    for(i=0;i< NOFILE;++i)//关闭打开的文件描述符 
    close(i); 
    chdir("/tmp");//改变工作目录到/tmp 
    umask(0);//重设文件创建掩模 
    return; 

    2. test.c清单 
    #include < stdio.h > 
    #include < time.h > 

    void init_daemon(void);//守护进程初始化函数 

    main() 

    FILE *fp; 
    time_t t; 
    init_daemon();//初始化为Daemon 

    while(1)//每隔一分钟向test.log报告运行状态 

    sleep(60);//睡眠一分钟 
    if((fp=fopen("test.log","a")) >=0) 

    t=time(0); 
    fprintf(fp,"Im here at %s/n",asctime(localtime(&t)) ); 
    fclose(fp); 



    以上程序在RedHat Linux6.0下编译通过。步骤如下: 
    编译:gcc -g -o test init.c test.c 
    执行:./test 
    查看进程:ps -ef 
    从输出可以发现test守护进程的各种特性满足上面的要求。

    展开全文
  • linux 守护进程

    2016-04-21 21:24:41
    Linux 守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。它不需要用户输入就能运行而且提供某种服务,不是对整个系统就是对...

    项目github地址:bitcarmanlee easy-algorithm-interview-and-practice
    欢迎大家star,留言,一起学习进步

    Linux 守护进程概述
    Linux Daemon(守护进程)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。它不需要用户输入就能运行而且提供某种服务,不是对整个系统就是对某个用户程序提供服务。Linux系统的大多数服务器就是通过守护进程实现的。常见的守护进程包括系统日志进程syslogd、 web服务器httpd、邮件服务器sendmail和数据库服务器mysqld等。

    守护进程一般在系统启动时开始运行,除非强行终止,否则直到系统关机都保持运行。守护进程经常以超级用户(root)权限运行,因为它们要使用特殊的端口(1-1024)或访问某些特殊的资源。

    一个守护进程的父进程是init进程,因为它真正的父进程在fork出子进程后就先于子进程exit退出了,所以它是一个由init继承的孤儿进程。守护进程是非交互式程序,没有控制终端,所以任何输出,无论是向标准输出设备stdout还是标准出错设备stderr的输出都需要特殊处理。

    工作原理
    Linux 守护进程的工作模式是服务器/客户机(Server/Client),服务器在一个特定的端口上监听(Listen)等待客户连接,连接成功后服务器和客户端通过端口进行数据通信。守护进程的工作就是打开一个端口,并且监听(Listen)等待客户连接。如果客户端产生一个连接请求,守护进程就创建(Fork)一个子服务器响应这个连接,而主服务器继续监听其他的服务请求。

    工作模式
    Linux 守护进程有两种工作模式:stand-alone模式和xinetd模式。
    (1)stand-alone模式
    独立运行的守护进程由init负责管理,所有独立运行守护进程的脚本在/etc/rc.d/init.d/目录下。独立运行的守护进程工作方式称作stand-alone,是Unix传统的C/S模式的访问模式。服务器监听(Listen)在一个特点的端口上等待客户端的联机。如果客户端产生一个连接请求,守护进程就创建(Fork)一个子服务器响应这个连接,而主服务器继续监听。工作在stand-alone模式下的网络服务有route、gated、web服务器等。在Linux系统中通过stand-alone工作模式启动的服务由/etc/rc.d/下面对应的运行级别当中的符号链接启动。

    (2)xinetd模式
    从守护进程的概念可以看出,对于系统所要求的每一种服务,都必须运行一个监听某个端口连接所发生的守护进程,这意味着资源浪费。为了解决这个问题,Linux引进了"网络守护进程服务程序"的概念。Redhat Linux使用的网络守护进程是xinted(eXtended InterNET Daemon)。和stand-alone模式相比xinetd模式也称 InternetSuper-Server(超级服务器)。xinetd能够同时监听多个指定的端口,在接受用户请求时,他能够根据用户请求的端口不同,启动不同的网络服务进程来处理这些用户请求。可以把xinetd看做一个管理启动服务的管理服务器,它决定把一个客户请求交给那个程序处理,然后启动相应的守护进程。

    和stand-alone工作模式相比,系统不必为每一个网络服务进程监听其服务端口,运行xinetd守护进程就可以同时监听所有服务端口,这样就降低了系统开销,保护系统资源。但是对于访问量大、经常出现并发访问时,xinetd想要频繁启动对应的网络服务进程,反而会导致系统性能下降。一般来说系统一些负载高的服务,比如Apache、sendmail等服务是单独启动的。而其他服务类型都可以使用xinetd超级服务器管理。

    查看系统为Linux服务提供那种模式方法在Linux命令行可以使用pstree命令可以看到两种不同方式启动的网络服务。

    展开全文
  • Linux守护进程

    2017-02-26 17:00:16
    我们在图中看到,图中所列举的这些都是与控制终端无关的进程,在Linux中我们称这些进程为守护进程,也叫做精灵进程,今天我们就来谈一谈Linux下面的守护进程把。什么是守护进程守护进程也被称为精灵进

    首先,我们在Linux的shell下面运行一条指令ps -ajx,其中 ps是查看当前系统进程状态的指令,-a显示由其它用户所拥有的进程的状态,-x显示没有控制终端的进程的状态,-j显示与作业相关的信息。
    (守护进程1)

    我们在图中看到,图中所列举的这些都是与控制终端无关的进程,在Linux中我们称这些进程为守护进程,也叫做精灵进程,今天我们就来谈一谈Linux下面的守护进程把。


    什么是守护进程?

    守护进程也被称为精灵进程,是运行在后台的一种特殊的进程,它独立于终端并且周期性的执行某种任务。他们的生期很长,在系统引导装入时启动,仅在系统关闭时才停止(注意这里是停止,而不是终止)。


    守护进程的特征

    如上图,我们发现所有的守护进程首先他们是没有控制终端的,即他们独立于终端(他们的终端名被设置为?)。其中内核守护进程以控制终端的方式启动,用户层守护进程缺少控制终端是因为他们调用了setsid函数的结果;后面我们将会提到。许多用户层的守护进程都是进程组的组长进程,以及会话的首进程,即他们自成进程组,自成会话。,最后所有用户层守护进程的父进程都是init进程。

    怎样创建一个用户层的守护进程

    创建一个用户层守护进程的步骤如下:
    1. 首先,调用umask函数设置文件权限,这是因为守护进程可能会创建某些文件,所以我们要设定特定的权限。
    2. 调用fork函数,然后让父进程被终止;这样做的原因是因为下面我们要调用setsid函数创建会话,因为setsid函数不能被组长进程调用,而如果我们只创建一个进程,然后再让这个进程创建子进程,那么父进程一定是组长进程,让父进程终止的原因是因为有一条规则叫做孤儿进程的领养机制,这样我们就能保证子进程的父进程为1号进程了。
    3. 调用setsid函数创建一个新的会话;下面我们先来看看setsid函数把:

           #include <unistd.h>
    
           pid_t setsid(void);
    

    这个函数的功能主要有下面几点:

    • 调用该函数的当前进程成为所创建会话的首进程,此外,当前进程时会话中的唯一进程。
    • 该进程创建了一个新的进程组,并成为组长进程。
    • 调用完该函数后,该进程就没有控制终端了,因为setsid函数会切断当前进程与其控制终端的联系,使其独立于终端。
    • 还有一点是,如果调用进程已经是一个进程组的组长,那么该函数会出错。

      在了解了这个函数后,我们发现,这个函数是创建守护进程的关键的步骤,因为守护进程没有控制终端,守护进程自成会话和进程组。

      1. 因为守护进程的工作目录大部分都在跟目录,所以我们通过chdir函数,将守护进程的工作目录设置为根目录。
      2. 下面我们关闭文件描述符,因为在守护进程中这些文件描述符是多余的,如果不关闭让守护进程占着的话是一种对资源的浪费。
      3. 忽略SIGCHLD信号,守护进程默认也是这样做的。

    下面,基于这些步骤,我们来编写自己的守护进程把:

    /*************************************************************************
        > File Name: mydemon.c
        > Author: LZH
        > Mail: 597995302@qq.com 
        > Created Time: Fri 24 Feb 2017 11:33:38 PM PST
     ************************************************************************/
    
    #include<stdio.h>
    #include<unistd.h>
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<signal.h>
    #include<stdlib.h>
    
    #define PATH "/"          //创建的守护进程的工作目录
    void mydemond()
    {
      umask(0);
      pid_t pid=fork(); 
      if(pid > 0){
          exit(0);                    //这里让父进程终止,然后子进程调用setsid函数创建会话
      }
      pid_t sid=setsid();
      if(sid==-1){
          perror("setsid...");
          exit(1);
      }
    
      if(chdir(PATH)!=0)
      {
        perror("chdir..."); 
        exit(1);    
      }
      close(0);
      close(1);
      close(2);
      signal(SIGCHLD,SIG_IGN);
    }
    
    int main()
    {
        mydemond();
        while(1){
            sleep(1);
        }
        return 0;
    }
    
    
    ----------
    
    

    下面我们来运行一下守护进程,查看结果:
    (守护进程2)

    下面我们在注销掉当前终端,看看守护进程的状态。
    (守护进程3)


    创建守护进程fork两次

    下面我们来换一种思路,我们在创建守护进程时fork两次来看看会有什么结果!

    /*************************************************************************
        > File Name: mydemon.c
        > Author: LZH
        > Mail: 597995302@qq.com 
        > Created Time: Fri 24 Feb 2017 11:33:38 PM PST
     ************************************************************************/
    
    #include<stdio.h>
    #include<unistd.h>
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<signal.h>
    #include<stdlib.h>
    
    #define PATH "/"
    void mydemond()
    {
      umask(0);
      pid_t pid=fork();
      if(pid > 0){
          exit(0);
      }
      else{
          //fork once child
         pid_t sid=setsid();
         if(sid==-1){
          perror("setsid...");
          exit(1);
          }
          pid_t newpid=fork();
          if(newpid > 0){
              //fork twice father
              exit(0);
          }
    
      if(chdir(PATH)!=0)
      {
        perror("chdir..."); 
        exit(1);    
      }
      close(0);
      close(1);
      close(2);
      signal(SIGCHLD,SIG_IGN);
      }
    }
    
    int main()
    {
        mydemond();
        while(1){
            sleep(1);
        }
        return 0;
    }
    

    下面我们运行后来看看fork两次的守护进程的状态。
    (守护进程4)

    此时,守护进程已经不是自成会话和进程组了,那我们为什么要这样做呢?


    fork一次与fork两次的区别

    前面我们fork一次,是为了保证调用setsid函数的进程不是组长进程(因为setsid函数不允许组长进程调用),这时,我们创建出来的守护进程虽然独立于控制终端,但是由于它自成进程组,自成会话。所以作为一个会话首进程,它拥有打开一个控制终端的权利,如果他打开了一个控制终端,那么它就和守护进程独立于控制终端相互矛盾了,所以就有了fork两次。
    fork两次保证了第二次fork出来的孙子进程不是会话的首进程,所以这时我们在终止掉儿子进程,此时会话首进程被终止,所以这个会话中的其他进程就没有打开控制终端的权利了。


    下面我们来看看fork两次的步骤

    这里写图片描述

    展开全文
  • Linux 守护进程

    千次阅读 2018-08-26 11:06:13
     守护进程, 也就是通常所说的 daemon 进程, 是 Linux 中的后台服务进程。 它是一个生存期较长的进程, 通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。 守护进程常常在系统引导载入时启动...

    1. 守护进程概述

            守护进程, 也就是通常所说的 daemon 进程, 是 Linux 中的后台服务进程。 它是一个生存期较长的进程, 通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。 守护进程常常在系统引导载入时启动, 在系统关闭时终止。 Linux 有很多系统服务, 大多数服务都是通过守护进程实现的。 同时, 守护进程还能完成许多系统任务, 例如, 作业规划进程 crond、 打印进程 lqd 等(这里的结尾字母 d 就是 daemon 的意思)。

          由于在 Linux 中, 每一个系统与用户进行交流的界面称为终端, 每一个从此终端开始运行的进程都会依附于这个终端, 这个终端称为这些进程的控制终端, 当控制终端被关闭时,相应的进程都会自动关闭。 但是守护进程却能够突破这种限制, 它从被执行开始运转, 直到接收到某种信号或者整个系统关闭时才会退出。 如果想让某个进程不因为用户、 终端或者其他的变化而受到影响, 那么就必须把这个进程变成一个守护进程。 可见, 守护进程是非常重要的。


    2. 编写守护进程

         编写守护进程看似复杂, 但实际上也是遵循一个特定的流程, 只要将此流程掌握了, 就能很方便地编写出自己的守护进程。下面就分 4 个步骤来讲解怎样创建一个简单的守护进程。在讲解的同时, 会配合介绍与创建守护进程相关的几个系统函数, 希望读者能很好地掌握。
    (1) 创建子进程, 父进程退出。

          这是编写守护进程的第一步。 由于守护进程是脱离控制终端的, 因此, 完成第一步后就会在 shell 终端造成一种程序已经运行完毕的假象, 之后的所有工作都在子进程中完成, 而用户在 shell 终端则可以执行其他的命令, 从而在形式上做到与控制终端的脱离。
          到这里, 有心的读者可能会问, 父进程创建了子进程后退出, 此时该子进程不就没有父进程了吗? 守护进程中确实会出现这么一个有趣的现象: 由于父进程已经先于子进程退出,就会造成子进程没有父进程, 从而变成一个孤儿进程。 在 Linux 中, 每当系统发现一个孤儿进程时, 就会自动由 1 号进程(也就是 init 进程) 收养它, 这样, 原先的子进程就会变成 init进程的子进程。

    注意:在不同的Linux的发行版,出来孤儿进程给的进程号,不一样,也就是可能不是1号进程,大多是用户进程

    其关键代码如下:

    pid = fork();
    if (pid > 0)
    {
    exit(0); /* 父进程退出 */
    }

    (2) 在子进程中创建新会话。

            这个步骤是创建守护进程最重要的一步, 虽然实现非常简单, 但意义却非常重大。 在这里使用的是系统函数 setsid(), 在具体介绍 setsid()之前, 读者首先要了解两个概念: 进程组和会话期。
         进程组。 进程组是一个或多个进程的集合。 进程组由进程组 ID 来唯一标识。 除了进程号(PID) 之外, 进程组 ID 也是一个进程的必备属性。每个进程组都有一个组长进程, 其组长进程的进程号等于进程组 ID, 且该进程 ID 不会因组长进程的退出而受到影响,组长结束会宣称新组长,进程组的结束是最后一个进程的结束。
         会话期。 会话组是一个或多个进程组的集合。 通常, 一个会话开始于用户登录, 终
    止于用户退出, 在此期间该用户运行的所有进程都属于这个会话期。 进程组和会话
    期之间的关系如图  所示。

    接下来就可以具体介绍 setsid()的相关内容。
    ① setsid()函数的作用。 setsid()函数用于创建一个新的会话组, 并担任该会话组的组长。
    调用 setsid()有以下 3 个作用:
     让进程摆脱原会话的控制。
     让进程摆脱原进程组的控制。
     让进程摆脱原控制终端的控制。

    那么, 在创建守护进程时为什么要调用 setsid()函数呢? 读者可以回忆一下创建守护进
    程的第一步, 在那里调用了 fork()函数来创建子进程再令父进程退出。 由于在调用 fork()函
    数时, 子进程全盘复制了父进程的会话期、 进程组和控制终端等, 虽然父进程退出了, 但原
    先的会话期、 进程组和控制终端等并没有改变, 因此, 还不是真正意义上的独立。 而 setsid()
    函数能够使进程完全独立出来, 从而脱离所有其他进程的控制。


    ② setsid()函数格式。 表 列出了 setsid()函数的语法要点。

    (3) 改变当前目录为根目录。

        这一步也是必要的步骤。 使用 fork()创建的子进程继承了父进程的当前工作目录。 由于在进程运行过程中, 当前目录所在的文件系统(如“/mnt/usb”等) 是不能卸载的, 这对以后的使用会造成诸多的麻烦(如系统由于某种原因要进入单用户模式)。 因此, 通常的做法是让“/” 作为守护进程的当前工作目录, 这样就可以避免上述问题。 当然, 如有特殊需要, 也可以把当前工作目录换成其他的路径,如/tmp。 改变工作目录的常见函数是 chdir()。


    (4) 重设文件权限掩码。

          文件权限掩码是指屏蔽掉文件权限中的对应位。 例如, 有一个文件权限掩码是 050, 它就屏蔽了文件组拥有者的可读与可执行权限。 由于使用 fork()函数新建的子进程继承了父进程的文件权限掩码, 这就给该子进程使用文件带来了诸多的麻烦。因此, 把文件权限掩码设置为 0, 可以大大增强该守护进程的灵活性。 设置文件权限掩码的函数是 umask()。 在这里, 通常的使用方法为 umask(0)。


    (5) 关闭文件描述符。

         同文件权限掩码一样, 用 fork()函数新建的子进程会从父进程那里继承一些已经打开的文件。 这些被打开的文件可能永远不会被守护进程读或写, 但它们一样消耗系统资源, 而且可能导致所在的文件系统无法被卸载。在上面的第(2) 步之后, 守护进程已经与所属的控制终端失去了联系, 因此, 从终端输入的字符不可能达到守护进程, 守护进程中用常规方法(如 printf()) 输出的字符也不可能在终端上显示出来。

    所以, 文件描述符为 0、 1 和 2 的 3 个文件(常说的输入、 输出和报错这 3 个文件) 已经失去了存在的价值, 也应被关闭。 通常按如下方式关闭文件描述符:
     

    for(i = 0; i < MAXFILE; i++)
    {
    close(i);
    }

    这样, 一个简单的守护进程就建立起来了。 创建守护进程的流程图如图  所示。

    下面是实现守护进程的一个完整实例,该实例首先按照以上的创建流程建立了一个守护进程, 然后让该守护进程每隔 10s 向日志文件/tmp/daemon.log 写入一句话。
     

    /* daemon.c 创建守护进程实例 */
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<fcntl.h>
    #include<sys/types.h>
    #include<unistd.h>
    #include<sys/wait.h>
    int main()
    {
    	pid_t pid;
    	int i, fd;
    	char *buf = "This is a Daemon\n";
    	pid = fork(); /* 第一步 */
    	if (pid < 0)
    	{
    		printf("Error fork\n");
    		exit(1);
    	}else if (pid > 0)
    	{
    		exit(0); /* 父进程退出 */
    	} 
    	setsid(); /* 第二步 */
    	chdir("/"); /* 第三步 */
    	umask(0); /* 第四步 */
    	for(i = 0; i < getdtablesize(); i++) /* 第五步 */
    	{
    		close(i);
    	} /* 这时创建完守护进程, 以下开始正式进入守护进程工作 */
    	while(1)
    	{
    		if ((fd = open("/tmp/daemon.log", O_CREAT|O_WRONLY|O_APPEND, 0600)) < 0)
    		{
    			printf("Open file error\n");
    			exit(1);
    		}
    		write(fd, buf, strlen(buf) + 1);
    	close(fd);
    	sleep(10);
    	}
    	exit(0);
    }


    该程序下载到开发板上, 可以看到该程序每隔 10s 就会在对应的文件中输入相关内容,
    并且使用 ps 可以看到该进程在后台运行, 结果如下:
    $ tail -f /tmp/daemon.log
    This is a Daemon
    This is a Daemon
    This is a Daemon
    This is a Daemon

    $ps -ef|grep daemon
    76 root 1272 S ./daemon
    85 root 1520 S grep daemon


    3. 守护进程的输出消息处理

          读者在前面编写守护进程的具体调试过程中会发现,由于守护进程完全脱离了控制终端,因此, 不能像其他普通进程一样将错误信息输出到控制终端来通知程序员, 即使使用 gdb也无法正常调试。 那么, 守护进程的进程要如何调试呢? 一种通用的办法是使用 syslog 服
    务, 将程序中的出错信息输入到系统日志文件中(如“/var/log/messages”), 从而可以直观地看到程序的问题所在(“/var/log/message” 系统日志文件只能由拥有 root 权限的超级用户查看。 在不同 Linux 发行版本中, 系统日志文件路径全名可能有所不同, 例如, 可能是
    “/var/log/syslog”)。syslog 是 Linux 中的系统日志管理服务, 通过守护进程 syslogd 来维护。 该守护进程在启动时会读一个配置文件“/etc/syslog.conf”, 该文件决定了不同种类的消息会发送到何处。


    例如, 紧急消息可被送到系统管理员并在控制台上显示, 而警告消息则可被记录到一个文件中。
    该机制提供了 3 个 syslog 相关函数, 分别为 openlog()、 syslog()和 closelog(), 下面就分别介绍这 3 个函数。
    1) syslog 相关函数说明

    openlog()函数用于打开系统日志服务的一个链接;

    syslog()函数用于向日志文件中写入消息, 在这里可以规定消息的优先级、 消息输出格式等;

    closelog()函数用于关闭系统日志服务的链接。

     (1)openlog()函数语法要点

    (2)列出了 syslog()函数的语法要点   ...表示变量的数量可变

    实例:    syslog(LOG_NOTICE,"I LOVE YOU %dyear\n",10000);

    (3)列出了 closelog()函数的语法要点

    3) 使用实例
    这里将上一个示例程序用 syslog 服务进行重写, 其中有区别的地方用加粗的字体表示,
    源代码如下:
     

    /* syslog_daemon.c 利用 syslog 服务的守护进程实例 */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/wait.h>
    #include <syslog.h>
    int main()
    {
    	pid_t pid, sid;
    	int i, fd;
    	char *buf = "This is a Daemon\n";
    	pid = fork(); /* 第一步 */
    	if (pid < 0)
    	{
    		printf("Error fork\n");
    		exit(1);
    	}else if (pid > 0)
    	{
    		exit(0); /* 父进程退出 */
    	} /* 打开系统日志服务, openlog */
    	openlog("daemon_syslog", LOG_PID, LOG_DAEMON);
    	if ((sid = setsid()) < 0) /* 第二步 */
    	{
    		syslog(LOG_ERR, "%s\n", "setsid");
    		exit(1);
    	} 
    	if ((sid = chdir("/")) < 0) /* 第三步 */
    	{
    		syslog(LOG_ERR, "%s\n", "chdir");
    		exit(1);
    	} 
    	umask(0); /* 第四步 */
    	for(i = 0; i < getdtablesize(); i++) /* 第五步 */
    	{
    	close(i);
    	} /* 这时创建完守护进程, 以下开始正式进入守护进程工作 */
    	while(1)
    	{
    		if ((fd = open("/tmp/daemon.log", O_CREAT|O_WRONLY|O_APPEND, 0600)) < 0)
    		{
    			syslog(LOG_ERR, "open");
    			exit(1);
    		} 
    		write(fd, buf, strlen(buf) + 1);
    		close(fd);
    		sleep(10);
    	} 
    	closelog();
    	exit(0);
    }

    读者可以尝试用普通用户的身份执行此程序。

    由于这里的 open()函数必须具有 root 权限,
    因此, syslog 会将错误信息写入到系统日志文件(如“/var/log/messages”) 中,

    但是对于ubuntu来说,日志文件在/var/log/syslog中

    cat /var/log/syslog

    结果如下:
    Jan 30 18:20:08 localhost daemon_syslog[612]: open

     

     


     

    展开全文
  • Linux守护进程编写

    2019-04-12 00:09:38
    Linux守护进程编写 环境:VMware 15 + ubuntu 16 护进程的特点 后台服务程序,随系统启动而启动。 很多系统服务通过守护进程完成。 守护进程的名字往往以字母‘d’结尾 生存周期长。系统装入时...
  • linux守护进程的编写

    千次阅读 2018-10-23 20:57:42
    Linux守护进程 了解守护进程的特点 了解ps中查看守护进程的方法 了解会话相关概念 掌握编写守护进程的方法 一、基础知识 1)进程的类型,进程大体分为三类  (1)交互进程  (2)批处理进程  (3)守护进程 2...
  • Linux 守护进程 详解

    2017-06-22 11:00:19
    Linux 守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。它不需要用户输入就能运行而且提供某种服务,不是对整个系统就是对...
  • linux 守护进程实例

    2013-12-23 10:36:53
    Linux 守护进程的编程方法 守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。Linux的大多数服务器就是用守护...
  • 何为守护进程 、进程组 / 组长进程 / 会话 / 会话首进程 、守护进程的创建步骤 、创建守护进程程序示例
  • Linux守护进程的编程实现

    千次阅读 2015-10-07 00:49:36
    Linux 守护进程的编程方法 守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。Linux的大多数服务器就是用守护...
  • Linux守护进程的编程实现 Linux 守护进程的编程方法 守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。...
  • Linux 守护进程的编程方法  守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。Linux的大多数服务器就是用守护...
  • linux守护进程启动jar包的命令

    千次阅读 2020-04-16 21:34:41
    linux守护进程启动jar包的命令 nohup java -jar 你的jar包名 & 注意: 这样启动是看不到日志的
  • Linux 守护进程的编程方法 linux上编写守护进程的例程 Linux下后台守护进程的编写实例 一、守护进程及其特性  守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种...
  • Linux守护进程列表

    2012-02-20 22:33:05
    Linux启动时需要加载很多服务,提供这些服务的程序是由运行在后台的守护进程来执行的。守护进程是生存期长的一种进程。它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。...Linux守护进程

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 112,399
精华内容 44,959
关键字:

linux守护进程

linux 订阅