tlpi:DAEMON

DAEMON(守护进程)

1.特征

DAEMON是一种具备以下特征的进程

  • 它的生命周期很长,通常,一个DAEMON会在系统启动时被创建,运行至系统终止
  • 它在后台运行并且不具有控制终端,这确保了内核不会为其生成任何的作业控制信号(SIGTTIN、SIGTOUT等)以及终端相关信号(SIGINT, SIGSTOP等)

一些常见的daemon:

  • cron:一个在规定时间执行命令的daemon
  • sshd:安全shell daemon,允许在远程主机上使用一个安全的通信协议来登录系统
  • httpd:HTTP服务器daemon,用于服务Web页面
  • inetd:Internet超级服务器daemon,监听从指定TCP/IP端口进入的网络连接并启动相应的网络应用程序来处理这些连接
2.创建一个daemon

创建一个daemon,一般需要完成以下步骤

  1. 执行一个fork(),然后父进程退出,子进程继续执行(此时子进程会被init进程收养)

    有以下两个原因:

    • 如果daemon是从命令行启动的,那么当父进程终止时,shell会接收到SIGCHLD信号,接着shell成为前台进程,刚刚创建出的子进程会自动的在后台运行
    • 子进程继承了父进程的进程组ID,然而它的父进程终止了,子进程的进程ID与进程组ID并不相同,即它并非进程组首进程,这样做为后面的步骤提供了保障
  2. 子进程调用setsid()开启一个新的会话,它与之前的控制终端的关联将会被完全断开

  3. 如果daemon在运行过程中不会打开终端设备文件,那么就无须担心其会请求一个控制终端

    如果daemon在运行过程中可能会打开一个终端设备,那么就需要采取措施使得该终端设备不会成为控制终端,方法有二:

    • 在使用open()打开终端文件时指定O_NOCTTY标志

    • 在子进程使用setsid()之后再次使用fork(),然后舍弃子进程,保留孙子进程,这样做确保了孙子进程不会成为会话首进程

      (在Linux中,只有会话首进程在打开终端时才会让该终端成为控制终端)

  4. 清除进程的umask以确保daemon创建文件和目录式具有所需要的权限

  5. 修改进程的工作目录,通常是’/'

    这样做主要是为了确保在系统关闭时能够正常的卸载文件系统,如果daemon在某一个别的目录,而该目录下由于守护进程当前正在运行,就会处于busy状态,导致该目录的文件系统无法被卸载。也可以将工作目录修改为任意一个永远不会被卸载的目录,如完成任务时所在的目录或者是配置文件中定义的一个目录

  6. 关闭daemon从其父进程继承而来的所有打开着的文件描述符(可选)

    除非daemon可能需要保持文件描述的打开状态,否则一般都会关闭,原因有二:

    • daemon失去了终端并且在后台运行,因此让它保持文件描述符0,1,2毫无意义,因为它们即执行控制终端
    • 无法卸载长时间打开着的daemon打开的文件的文件系统
  7. 打开/dev/null设备文件并且使用dup2()使所有的这些描述符指向这个设备

    原因也有二:

    • 确保了daemon在调用在这些文件描述符上执行I/O操作时不会出现失败的情况
    • 防止daemon使用文件描述符1,2打开文件进行读写导致原有的标准输出和标准错误的数据被破坏(不是很懂…)
3.编写daemon指南
  • 信号处理

​ 通常的daemon在在系统关闭时都会执行一些特定脚本文件来停止,可如果不以这种方式终止,那么daemon就会收到一个SIGTERM信 号,因为init进程在系统关闭时会向它的所有子进程发送该信号,如果自己编写的话,需要编写一个在5秒内完成工作的信号处理程序, 因为在5秒后,Init会再次发送一个SIGKILL信号

  • 内存泄漏问题

    由于daemon在系统中长时间运行,所以需要注意内存的泄漏问题

  • 多个实例

    一般需要确保系统中统一时刻只有一个daemon实例处于活跃状态

4.使用syslog记录消息和错误处理

syslog是一个集中式日志工具,系统中的所有应用程序都可以使用该工具来记录日志消息

syslog工具有两个基本组件:syslogd daemon和 syslogAPI

  • syslogd daemon

    如图(如果没有的话记得sudo apt-get install inetutils-syslogd)
    在这里插入图片描述

syslogAPI

  • 建立一个到系统日志的连接

    openlog()函数的调用是可选的,它建立一个到系统日志工具的连接之后并且为后续的syslog()调用设置默认设置

    #include<syslog.h>
    void openlog(const char *ident, int log_opentions, int facility);
    

    参数解释:

    • ident

      ident是一个指向字符串的指针,syslog()输出的每条消息都会包含这个字符创,这个参数的取值通常为程序名

    • log_options

      一个位掩码,包含LOG_NDELAY, LOG_NOWAIT等(查手册去吧你!),默认是LOG_ODELAY

    • facility

      用于标识消息的类型
      在这里插入图片描述

  • 记录一条日志消息

    #includeK<syslog.h>
    void syslog(int priority, const char *format, ...);
    

    参数解释:

    • priority

      priority是facility和level的OR值,省略的话则取默认值(openlog())

      levle可选值如下

在这里插入图片描述

  • format

    格式控制字符,比如可以这么写

    syslog(priority, "%s", string);
    
  • 关闭日志

    当完成日志记录之后可以使用closelog()来释放分配给/dev/log socket的文件描述符,基本不用,因为daemon一般都运行至系统终止

    #include<syslog.h>
    void closelog(void);
    
  • 过滤日志消息

    #include<syslog.h>
    int setlongmask(int mask_priority);
    						//成功:返回之前的日志掩码
    

    所有不在mask_priority中的掩码设置都会被丢弃

    • 有用的LOG_MASK()与LSG_UPO()宏

      LOG_MASK()会将level值转换为掩码,LOG_UPTO()创建一个能过滤特定级别以及以上的所有消息的位掩码

日志消息写在哪?

看/etc/syslog.conf文件吧,具体语法不说了,上网查,记得下载syslogd

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值