作者:isshe
日期:2016.10.30
邮箱:i.sshe@outlook.com
github: https://github.com/isshe
1. 相关概念
- 系统进程以赖于操作系统实现。
- 父进程ID为0的各进程通常是内核进程,它们作为系统引导装入过程的一部分而启动。
- 内核守护进程以无控制终端方式启动,用户层守护进程缺少控制终端可能是守护进程调用了setsid的结果。
- 大多数用户层守护进程都是进程组的组长进程以及会话的首进程,而且是这些进程组和会话中的唯一进程。(rsyslogd例外,linux中)
- 用户层守护进程的父进程是init进程(linux系统中)。
- 守护进程常作服务器进程。
2. 编写规则
编写守护进程程序时需遵循一些基本规则,以防产生不必要的交互。
- 1.调用umask将文件模式创建屏蔽字设置为一个已知值(通常是0)(不理解)
2.调用fork,然后父进程exit。这样可以:
如果该守护进程是为一条简单的shell命令启动的,那么父进程终止会让shell认为这条命令已经执行完毕。
子进程继承父进程的进程组ID,但获得新的进程ID,保证了子进程不是一个进程组的组长进程。3.调用setsid创建一个新会话。 会发生:(因为前面保证了此进程不是进程组的组长,所以可以创建新会话,否则,setsid会返回出错)
1). 该进程编程新会话的会话首进程(session leader),此时此进程是会话中唯一进程。
2). 该进程成为新进程组的组长进程。(新进程组ID就是调用进程ID)
3). 进程没有控制终端。4.将当前工作目录更改为根目录。
- 5.关闭不需要的文件描述符。(可以使用open_max函数或getrlimit函数获取最大文件描述符值)
- 6.某些进程打开/dev/null使其具有文件描述符0、1、2。
3. 出错记录
- 由于没有控制终端,不能简单地输出到标准错误上。
- 每个守护进程的出错信息写到一个文件也不好,管理起来会十分麻烦。
3.1 syslog
syslog设施的详细组织结构:
三种产生日志消息的方法:
- 内核例程可以调用log函数。任何一个用户进程可以通过打开(open)并读取(read)/dev/klog设备来读取这些信息。
- 调用syslog函数产生日志消息。
- 无论用户进程是在此主机上,还是通过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 mask);
- 功能:(日志消息通过syslogd守护进程读取)
- openlog:打开该进程的日志。(调用是可选的。如不调用,则在第一次调用syslog时自动调用。)
- closelog:关闭用于与syslogd守护进程进行通信的描述符。(也是可选的。)
- syslog:产生一个日志消息。
- setlogmask:用于设置进程的记录优先级屏蔽字。
参数:
- ident:可以被加到每则日志中的标识。一般是程序名称。
open:(以下表格不完全完整,完整见APUE p378)
option XSI 说明 LOG_CONS * 若日志消息不能通过UNIX域数据表送至syslogd,则将该消息写至控制台。 LOG_NDELAY * 立即打开至syslogd守护进程的UNIX域数据报套接字,不要等到第一条消息已经被记录时再打开。(通常,在记录第一条消息之前,不打开该套接字) LOG_NOWAIT * 不要等待在将消息记入日志过程中可能已创建的子进程。 LOG_ODELAY * 在第一条消息被记录之前延迟打开至syslogd守护进程的连接。 LOG_PERROR 将日志消息发送给syslogd外,还将它写到标准错误。 LOG_PID * 记录每条消息都要包含进程ID facility:设置facility参数的目的是可以让配置文件说明,来自不同设施的消息将以不同的方式处理。(中文表格见APUE p378)
- priority:是facility和level的组合,以下是level的表格:
- format:format参数以及其他所有format后的参数,都传至vsprintf函数一遍进行格式化。format中每个%m字符都先被替换成与errno值对应的strerror。
- mask:记录优先级屏蔽字。
- 返回值:
- setlogmask:返回调用setlogmask之前的屏蔽字。
3.2 实例
openlog("lpd", LOG_PID, LOG_LPR);
syslog(LOG_ERR, "open error for %s: %m", filename);
或
syslog(LOG_ERR|LOG_LPR, "open error for %s: %m", filename);
4. 守护进程的惯例
- 在UNIX系统中,守护进程通常遵循下列通用惯例:
- 若守护进程使用锁文件,那么该文件通常存储在/var/run目录中。(需要特权才能创建文件,锁的名字通常是name.pid,其中name是该守护进程或服务的名字)
- 若守护进程支持配置选项,那么配置文件通常存放在/etc目录中。(配置文件名字通常是namd.conf,name同上)
- 守护进程可用命令行启动,但通常它们是系统初始化脚本之一启动的(脚本如:/etc/rc* 或 /etc/init.d/*)。(如要终止后自动重启,则在/etc/inittab中为该守护进程宝货respawn记录项)
- 若一个守护进程有一个配置文件,那么当该守护进程启动时会读该文,但此后一般不会再查看它。
5. 参考资料
- 《unix环境高级编程》第13章