1、实现一个守护进程的实例如下:
#include "unp.h"
#include <syslog.h>
#define MAXFD 64
extern int daemon_proc;
void daemon_init(const char * pname,int facility){
int i;
pid_t pid;
if((pid = Fork())!=0) //调用fork,终止父进程,留下子进程继续运行。
exit(0);
setid(); //创建一个新的登陆会话session
Signal(SIGHUP,SIG_IGN); //忽略SGIHUP信号并在此调用fork
if((pid=Fork())!=0) //确保将来即使打开一个终端设备,也不会自动获得控制终端。
exit(0);
daemon_proc = 1; //非零时,出错处理函数将调用syslog函数取代fprintf输出到标准错误输出
chdir("/");
umask(0);//将工作目录改到根目录
for(i=0;i<MAXFD;i++) //关闭守护进程从运行开始打开的所有文件描述字
close(i);
openlog(pname,LOG_PID,facility);
}
2、实现一个守护进程最重要的两步就是:fork子进程,退出父进程;调用setsid()函数创建会话。我在一个练习中就只使用了这两步,没有像1中的示例一样再做其他的操作如更改掩码、关闭描述符操作等。代码如下:
if(fork() > 0) //第1步
exit(0);
setsid(); //第2步
if(fork() > 0)//第3步:确保将来即使打开一个终端设备,也不会自动获得控制终端。
exit(0);
之所以需要第3步是因为:在svr4中,当没有控制终端的会话头进程打开终端设备时(这个终端现在不是其他会话的控制终端),该终端自动成为这个会话头的控制终端。根据这个特点,如果没有第3步,那么第一次fork的子进程在调用setsid()创建一个新的会话之后,会成为这个会话组的组长即会话头,那么这个子进程就很可能在以后获得控制终端。加入了第3步之后,在子进程在创建一个子进程,孙子进程。孙子进程就不是子进程创建的会话的会话头,因此就不会再获得终端。
在练习中发现:虽然我加入了2中的代码将keymngserver进程变成了守护进程,但是却发现keymngserver中的printf仍然可以输出到启动keymngserver的终端。这可能是因为孙子进程中的文件描述符是从父进程中复制过来的,因此孙子进程(守护进程)拥有启动keymngserver的终端的描述符,所以可以输出到启动keymngserver的终端。当启动keymngserver的终端关闭之后,孙子进程(守护进程)还在后台运行,但是就无法再输出到终端了。
以下是一些结果: