📄 13.htm
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
<title>C:\WINDOWS\Desktop\UnixProg\7.htm</title>
</head>
<body>
<font SIZE="2">
<h1 align="center">第十三章 精灵进程 </h1>
<p>13.1 介绍 </p>
<p>精灵(Daemons)是生存期长的一种进程。它们常常在系统引导装入时启动,在系
</p>
<p>统关闭(shutdown)时终止。因为它们没有控制终端,所以我们说它们是在后台运
</p>
<p>行的。UNIX系统有很多精灵进程,它们执行日常事物活动。 </p>
<p>本章说明精灵的进程结构,以及如何编写精灵进程程序,因为精灵没有控制终端,
</p>
<p>我们需要了解在有关事物出问题时,精灵进程如何报告出错情况。
</p>
<p>13.2 精灵进程的特征 </p>
<p>让我们先来察看一些常用的系统精灵进程,以及它们怎样和第九章中所叙述的概念
</p>
<p>:进程组、控制终端和对话期相关联。ps(1)命令打印系统中各个进程的状态。该
</p>
<p>命令有多个选择项,有关细节请参考系统手册。为了察看本节讨论中所需的信息,
</p>
<p>在4.3+BSD或SUN OS 系统下执行: </p>
<p>ps -axj </p>
<p>选择项-a显示由其他用户(others)所拥有的进程的状态;-x显示没有控制终端的
</p>
<p>进程的状态。-j显示与作业有关的信息:对话期ID、进程组ID、控制终端以及终端
</p>
<p>进程组ID。在SVR4之下,与此相类似的命令是ps -efjc。(在某些符合"美国国防
</p>
<p>部安全性准则"要求的UNIX系统中,只能使用ps
查看自己所拥有的进程。)ps的输 </p>
<p>出大致是: </p>
<p>PPID PID PGID SID TT TPGID UID COMMAND </p>
<p>0 0 0 0 ? -1 0 </p>
<p>wapper </p>
<p>0 1 0 0 ? -1 0 </p>
<p>sbin/init - </p>
<p>0 2 0 0 ? -1 0 </p>
<p>agedaemon </p>
<p>1 80 80 80 ? -1 0 </p>
<p>yslogd </p>
<p>1 88 88 88 ? -1 0 </p>
<p>usr/lib/sendmail -bd -qlh </p>
<p>1 105 37 37 ? -1 0 </p>
<p>pdate </p>
<p>1 108 108 108 ? -1 0 </p>
<p>ron </p>
<p>1 114 114 114 ? -1 0 </p>
<p>netd </p>
<p>1 117 117 117 ? -1 0 </p>
<p>usr/lib/lpd </p>
<p>其中,已移去了一些我们并无兴趣的列,例如累计CPU时间。按照顺序,各列标题
</p>
<p>的意义是:父进程ID、进程ID、进程组ID、终端名称、终端进程组ID(与该控制终
</p>
<p>端相关的前台进程组)、用户ID以及实际命令字符串。 </p>
<p>这些ps命令在支持对话期ID的系统(SUN OS)上运行,我们曾在9.5节的sets
</p>
<p>id函数中提及对话期ID。它是对话期首进程的进程ID。但是,4.3+BSD系统将打印
</p>
<p>与本进程所属进程组对应的session结构的地址(见9.11) </p>
<p>进程0、1以及2是8.2节中所述的进程。这些进程非常特殊,存在于系统的整个生命
</p>
<p>期中。它们没有父进程ID,没有组进程ID,也没有对话期ID。syslogd精灵进程可
</p>
<p>用于任何为操作人员记录系统消息的程序。可以在一台实际的控制台上打印这些消
</p>
<p>息,也可将它们写到一个文件中(在13.4.2中将对syslog设施进行说明)。sendm
</p>
<p>ail是标准邮递精灵进程。update程序定期将核心缓存中的内容写到硬盘上(通常
</p>
<p>是每隔30秒)。为了做到这一点,该程序每隔30秒调用sync(2)函数一次(在4.
</p>
<p>24节中已对sync进行了说明)。cron精灵进程在指定的日期和时间执行指定的命令
</p>
<p>。许多系统管理任务是由cron定期地使相关程序执行而得以实现的。我们已在9.3
</p>
<p>节中提到inetd精灵进程。它监听系统的网络界面,以输入对各种网络服务器的请
</p>
<p>求。最后一个精灵进程,lpd,处理对系统提出的各个打印请求。 </p>
<p>注意,所有精灵进程都以超级用户(用户ID为0)的优先权运行。没有一个精灵进
</p>
<p>程具有控制终端-终端名称设置为问号(?)、终端前台进程组ID设置为-1。缺少
</p>
<p>控制终端可能是精灵进程调用了setsid的结果。除update以外的所有精灵进程都是
</p>
<p>进程组的首进程,对话期的首进程,而且是这些进程组和对话期中的唯一进程。u
</p>
<p>pdate是它所在进程组(37)和对话期(37)中的唯一进程,但是该进程组的首进
</p>
<p>程(可能也是该对话期的首进程)已经终止。最后,应当引起注意的是所有这些精
</p>
<p>灵进程的父进程都是init进程。 </p>
<p>13.3 编程规则 </p>
<p>在编写精灵进程程序时需遵循一些基本规则,以便防止产生并不希望的交互作用。
</p>
<p>下面先说明这些规则,然后是一个按照规则编写的函数daemon-init。 </p>
<p>1. 首先做的是调用fork,然后使父进程终止。这样做实现了下面几点。第一,如
</p>
<p>果该精灵进程是由一条简单shell命令启动的,那么使父进程终止使得shell认为这
</p>
<p>条命令已经执行完成。第二,子进程继承了父进程的进程组ID,但具有一个新的进
</p>
<p>程ID,这就保证了子进程不是一个进程组的首进程。这对于下面就要做的setsid调
</p>
<p>用是必要的前提条件。 </p>
<p>2. 调用setsid以创建一个新对话期。于是执行9.5节中列举的三个操作。使调用进
</p>
<p>程:(1)成为新对话期的首进程,(2)成为一个新进程组的首进程,(3)没有
</p>
<p>控制终端。 </p>
<p>在SVR之下,有些人建议在此时再调用fork,并使父进程终止。第二个子进程作为
</p>
<p>精灵进程继续运行。这样就保证了该精灵进程不是对话期首进程,于是按照SVR4规
</p>
<p>则(见9.6节)可以防止它取得控制终端。另一方面,为了避免取得控制终端,无
</p>
<p>论何时打开一个中断设备都要指定O-NOCTTY。 </p>
<p>3.
将当前工作目录更改为根目录。从父进程继承过来的当前工作目录可能在一个
</p>
<p>装配的文件系统中。因为精灵进程通常在系统再引导之前是一直存在的,所以如果
</p>
<p>精灵进程的当前工作目录在一个装配文件系统中,那么该文件系统就不能被拆卸。
</p>
<p>另外,某些精灵进程可能会把当前工作目录更改到某个指定位置,在此位置做它们
</p>
<p>的工作。例如,行式打印机假脱机精灵进程常常将其工作目录更改到它们的spool
</p>
<p>目录上。 </p>
<p>4. 将文件方式创建屏蔽字设置为0。由继承得来的文件方式创建屏蔽字可能会拒绝
</p>
<p>设置某些许可权。例如,若精灵进程要创建一个组可读、写的文件,而继承的文件
</p>
<p>方式创建屏蔽字,屏蔽了这两种许可权,则所要求的组可读、写就不能起作用。
</p>
<p>5.
关闭不再需要的文件描述符。这样使精灵进程就不再持有从其父进程继承来的
</p>
<p>某些文件描述符(父进程可能是shell进程,或某个其它进程)。但是,究竟关闭
</p>
<p>那些描述符则与具体的精灵进程有关,所以在下面的例子中不包含此步骤。可以使
</p>
<p>用程序2.3中的open_max函数来决定最高文件描述符值,并关闭直到该值的所有描
</p>
<p>述符。 </p>
<p>实例 </p>
<p>程序13.1是个函数,可由想初始化成为一个精灵进程的程序调用。 </p>
<p>#include <sys/types.h> </p>
<p>#include <sys/stat.h> </p>
<p>#include <fcntl.h> </p>
<p>#include "ourhdr.h" </p>
<p>int </p>
<p>daemon_init(void) </p>
<p>{ </p>
<p>pid_t pid; </p>
<p>if ( (pid = fork()) < 0) </p>
<p>return(-1); </p>
<p>else if (pid != 0) </p>
<p>exit(0); /* parent goes bye-bye */ </p>
<p>/* child continues */ </p>
<p>setsid(); /* become session leader */ </p>
<p>chdir("/"); /* change working directory */ </p>
<p>umask(0); /* clear our file mode creation mask */ </p>
<p>return(0); </p>
<p>} </p>
<p>程序13.1 初始化一个精灵进程 </p>
<p>若daemon-init函数由main函数调用,然后进入睡眠状态,那么我们可以用ps命令
</p>
<p>检查该精灵进程的状态: </p>
<p>$a.out </p>
<p>$ps_axj </p>
<p>PPID PID PGID SID TT TPGID UID COMMAND </p>
<p>1 735 735 735 ? -1 224 a.out </p>
<p>从中可以看到,该精灵进程已被正确地初始化。 </p>
<p>13.4 出错记录 </p>
<p>与精灵进程有关的一个问题是如何处理出错消息。因为它没有控制终端,所以不能
</p>
<p>只是写到标准出错输出上。在很多工作站上,控制台设备运行一个窗口系统,所以
</p>
<p>我们不希望所有精灵进程都写到控制台设备上。我们也不希望每个精灵进程将它自
</p>
<p>己的出错消息写到一个单独的文件中。对系统管理人员而言;如果要关心哪一个精
</p>
<p>灵进程写到哪一个记录文件中,并定期地检查这些文件,那么一定会使他感到头痛
</p>
<p>。所以,需要有一个集中的精灵进程出错记录设施。 </p>
<p>贝克莱开发了BSD syslog 设施,并广泛应用于4.2BSD。从4.×BSD导出的很多系统
</p>
<p>都支持syslog。在13.4.2中说明该设施。 </p>
<p>在系统V中,从来没有一个集中的精灵进程记录设施。SVR4支持BSD风格的syslog设
</p>
<p>施,在SVR4之下的inetd精灵进程使用syslog。在SVR中,syslog的基础是/dev/lo
</p>
<p>g流设备驱动程序,在下一节对此进行说明。 </p>
<p>13.4.1 SVR4流log驱动程序 </p>
<p>SVR4提供了一种流设备驱动程序,其界面具有流出错记录,流事件跟踪以及控制台
</p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -