守护进程

编程规则
编写守护进程程序时需遵循的一些基本规则,以防止产生不必要的交互作用:
- 先调用umask将文件模式创建屏蔽字设置为一个已知值(通常为0)
- 由继承得来的文件模式创建屏蔽字可能会被设置为拒绝某些权限
- 若守护进程要创建文件,则可能要设置特定的权限
- 继承的文件模式创建屏蔽字可能会屏蔽权限导致无法发挥作用
- 若守护进程调用的库函数创建了文件
- 则将文件模式创建屏蔽字设置为一个限制性更强的值可能会更明智
- 因为库函数可能不允许调用者通过一个显式的函数参数来设置权限
- 由继承得来的文件模式创建屏蔽字可能会被设置为拒绝某些权限
- 调用fork,然后使父进程exit
- 若守护进程是作为一条简单的shell命令启动的
- 则父进程终止会让shell认为这条命令已经执行完毕
- 虽然子进程继承了父进程的进程组ID,但获得了一个新的进程ID
- 这保证了子进程不是一个进程组的组长进程
- 这是下面调用setsid的先决条件
- 若守护进程是作为一条简单的shell命令启动的
- 调用setsid创建一个新会话
- 然后执行下列步骤,使调用进程:
- 成为新会话的首进程
- 成为一个新进程组的组长进程
- 没有控制终端
- 将当前工作目录更改为根目录
- 从父进程处继承而来的当前工作目录可能在一个挂载的文件系统中
- 因为守护进程通常在系统再引导之前是一直存在的
- 所以如果守护进程的当前工作目录在一个挂载的文件系统,则该文件系统就不能被卸载
- 或者,某些守护进程还可能会把当前工作目录改到某个指定位置,并在此位置进行它们的全部工作
- 关闭不再需要的文件描述符
- 使得守护进程不再持有从其父进程继承来的任何文件描述符(父进程可能是shell进程,或某个其他进程)
- 可以使用open_max函数 或 getrlimit函数来判定最高文件描述符值,并关闭直到该值的所有描述符
- 某些守护进程打开/dev/null使其具有文件描述符0、1、2
- 这样,任何一个试图读标准输入、写标准输出或标准错误的库例程都不会产生任何效果
- 因为守护进程并不与终端设备相关联,所以输出无处显示,也无处接收输入
- 即便守护进程是从交互式会话启动的,但守护进程运行在后台
- 所以登录会话的终止并不影响守护进程
- 这样,任何一个试图读标准输入、写标准输出或标准错误的库例程都不会产生任何效果
初始化为守护进程的程序调用:
1 | #include "apue.h" |
出错记录
集中的守护进程出错记录设施:syslog
3种产生日志消息的方法:
- 内核例程可以调用log函数
- 任何一个用户进程都可以通过打开(open)并读取(read)/dev/log设备来读取这些消息
- 大多数用户继承(守护进程)调用syslog(3)函数来产生日志消息
- 无论用户进程是在此主机上,还是通过TCP/IP网络连接到此主机的其他设备上
- 都可以把日志消息发向UDP端口514
- 注:syslog函数从不产生这些UDP数据报
- 它们要求产生此日志消息的进程进行显式的网络编程
syslogd守护进程启动时读取一个配置文件/etc/syslog.conf
该文件决定了不同种类的消息应送向何处
该设施的接口是syslog函数
1 | #include <syslog.h> |
调用openlog是可选的
如果不调用,第一次调用syslog时自动调用openlog
closelog也是可选的,只是关闭曾被用于与syslogd守护进程通信的描述符
openlog的参数
- ident参数:一般是进程的名称
- 会被加至每则日志消息中
- opention参数:指定各种选项的位屏蔽
- facility参数:可以让配置文件说明
- 来自不同设施的消息将以不同的方式进行处理
syslog产生一个日志消息
priority参数:是facility和level的组合%m
字符将被替换为与errno值对应的出错消息字符串
setlogmask用于设置进程的记录优先级屏蔽字
当设置了记录优先级屏蔽字时
各条消息除非已在记录优先级屏蔽字中进行了设置
否则不会被记录
logger命令是专门为以非交互方式运行的需要产生日志消息的shell脚本设计的
除了syslog,很多平台还提供了它的一种变体来处理可变参数列表
1 | #include <syslog.h> |
大多数syslog实现将使消息短时间处于队列中
- 如果在此期间有重复消息到达,则不会被写到日志记录中
- 而是输出一条类似:上条消息重复了N次 的消息
单实例守护进程
为了正常运作,某些守护进程会实现为:
在任一时刻只允许该守护进程的一个副本
文件和记录锁机制提供了一种方法
- 保证了一个守护进程只有一个副本在运行
- 如果每个守护进程创建一个有固定名字的文件,并在该文件的整体上加一把写锁
- 则只允许创建一把这样的写锁
- 在此之后创建写锁的尝试都会失败
- 这向后续守护进程副本指明已有一个副本正在运行
文件和记录锁提供了一种方便的互斥机制:
- 如果守护进程在一个文件的整体上得到一把写锁
- 则该守护进程终止时,这把锁将被自动删除
简化了复原所需的处理
- 则该守护进程终止时,这把锁将被自动删除
守护进程惯例
UNIX系统中,守护进程遵循下列通用惯例:
- 若守护进程使用锁文件,则该文件通常存储在/var/run目录中
- 需要注意:守护进程可能需要有超级用户权限才能在此目录下创建文件
- 锁文件的名字通常是name.pid
- name为守护进程或服务的名字
- 若守护进程支持配置选项,则配置文件通常存放在/etc目录中
- 配置文件的名字通常是name.conf
- name为该守护进程或服务的名字
- 配置文件的名字通常是name.conf
- 守护进程可用命令启动,但通常它们是由系统初始化脚本之一(
/etc/rc*
或/etc/init.d/*
)启动的- 如果在守护进程终止时,应当自动的重新启动它
- 则可在
/etc/inittab
中为该守护进程包括respawn记录项 - 这样init就将重新启动该守护进程
- 则可在
- 如果在守护进程终止时,应当自动的重新启动它
- 若一个守护进程有一个配置文件,则当该守护进程启动时会读取该文件,但在此之后一般就不会再查看它
- 若某个管理员更改了配置文件
- 则该守护进程可能需要被停止,然后再重新启动
- 以使配置文件的更改生效
- 为避免此种麻烦
- 某些守护进程将捕捉SIGHUP信号
- 当它们接收到该信号时,重新读配置文件
- 因为守护进程并不与终端相结合,所以没有理由期望接收SIGHUP
- 所以守护进程可以安全的重复使用SIGHUP
- 若某个管理员更改了配置文件
- 标题: 守护进程
- 作者: GuangYing
- 创建于 : 2025-03-08 22:22:24
- 更新于 : 2025-03-08 22:25:44
- 链接: http://quebo.cn/2025/03/08/守护进程/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。