unix高级环境编程 例子 代码实现练习 第十三章:守护进程

程序清单 13-1 初始化一个守护进程

/**
 * 程序清单 13-1 初始化一个守护进程 P343
 * zy:
 * 书上解释的很清楚了,我只是敲了一遍代码
 */
#include "apue.h"
#include <syslog.h>		//功能:记录至系统记录。
#include <fcntl.h> 		//File Control Operations
#include <sys/resource.h>	//sys/resource.h - definitions for XSI resource operations

void daemonize(const char *cmd){
	int i,fd0,fd1,fd2;
	pid_t pid;
	struct rlimit rl;
	struct sigaction sa;

	/**
	 * 清楚文件创建的屏蔽字
	 */
	umask(0);

	/**
	 * 拿到最大的文件描述符
	 */
	if(getrlimit(RLIMIT_NOFILE,&rl)<0){
		err_quit("%s,can't get file limit",cmd);
	}
	/**
	 * 成为会话首进程,并且没有控制TTY的权利
	 */
	if((pid=fork())<0){
		err_quit("%s,can't fork",cmd);
	}else if(pid!=0)
		exit(0);
	setsid();

	/**
	 * 下面再次使用一种机制确保不会拿到控制端控制权
	 */
	sa.sa_handler=SIG_IGN;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags=0;
	if(sigaction(SIGHUP,&sa,NULL)<0){
		err_quit("%s can't ignore SIGHUP");
	}
	if((pid=fork())<0){
		err_quit("%s,can't fork",cmd);
	}else if(pid!=0){//父进程退出
		exit(0);
	}
	/**
	 * 改变现在工作目录
	 */
	if(cddir("/")<0){
		err_quit("can't change directory");
	}


	/**
	 * 关闭所有的文件标识符
	 */
	if(rl.rlim_max==RLIM_INFINITY){
		rl.rlim_max=1024;//很奇怪,为什么要这样做
	}
	for(i=0;i<rl.rlim_max;i++){
		close(i);
	}
	/**
	 * 将文件标识符0、1、2都输出至/dev/null
	 */
	fd0=open("/dev/null",O_RDWR);
	fd1=dup(0);
	fd2=dup(0);

	/**
	 * 初始化log文件
	 */
	openlog(cmd,LOG_CONS,LOG_DAEMON); //P346 Open connection to system logger

	if(fd0!=0||fd1!=1||fd2!=2){ //因为上面把所有的FD都关了,所以才会是这个样子
		syslog(LOG_ERR,"unexpected file descriptors %d %d %d",fd0,fd1,fd2);
		exit(1);
	}


}

程序清单 13-2 保证只运行某个守护进程的一个副本

/**
 * 程序清单 13-2 保证只运行某个守护进程的一个副本 P349
 * zy:
 * 没什么特别要说的了 
 *
#include <unistd.h>		//对于类 Unix 系统,unistd.h 中所定义的接口通常都是大量针对系统调用的封装
						//(英语:wrapper functions),如 fork、pipe 以及
						//各种 I/O 原语(read、write、close 等等)
#include <stdlib.h>		//标准库函数的定义:定义了五种类型、一些宏和通用工具函数
#include <fcntl.h> 		//File Control Operations
#include <syslog.h>		//功能:记录至系统记录。
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>

#define LOCKFILE "/var/run/daemon.pid"
#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)

extern int lockfile(int); //这个函数在14.3节中会实现

int already_running(void){
	int fd;
	char buf[16];

	fd=open(LOCKFILE,O_RDWR|O_CREAT,LOCKMODE);
	if(fd<0){
		syslog(LOG_ERR,"can't open %s:%s",LOCKFILE,strerror(errno));
		exit(1);
	}
	if(lockfile(fd)<0){
		if(errno==EACCES||errno==EAGAIN){
			close(fd);
			return 1;
		}
		syslog(LOG_ERR,"can't lock %s:%s",LOCKFILE,strerror(errno));
		exit(1);
	}
	ftruncate(fd,0);
	sprintf(buf,"%ld",(long)getpid());
	write(fd,buf,strlen(buf)+1);
	return 0;
}

 程序清单 13-3 守护进程重读配置文件

/**
 * 程序清单 13-3 守护进程重读配置文件 P350
 * zy:
 * 这是使用了多线程和sigwait的方式
 */
#include <syslog.h>		//功能:记录至系统记录。
#include <pthread.h>
#include "apue.h"

sigset_t mask;

extern int already_running(void);

void reread(void){
	/*....*/
}
void *thr_fn(void *arg){
	int err,signo;
	err=sigwait(&mask,&signo);
	for(;;){
		if(err!=0){
				syslog(LOG_ERR,"sigwait failed");
				exit(1);
			}
			switch (signo) {
				case SIGHUP:
					syslog(LOG_INFO,"RE-reading configuration file");
					reread();
					break;
				case SIGTERM:
					syslog(LOG_INFO,"got SIGTERM; exiting");
					break;
				default:
					syslog(LOG_INFO,"unexpected signal %d \n",signo);
					break;
			}
	}
	return 0;
}

int main(int argc,char *argv[]){
	int err;
	pthread_t tid;
	char *cmd;
	struct sigaction sa;

	//下面这个if就是想拿到我们给守护线程取得名字
	if((cmd=strrchr(argv[0],'/'))==NULL){//查找一个字符c在另一个字符串str中末次出现的位置
		cmd=argv[0];
	}else{
		cmd++;
	}

	daemonize(cmd);

	/*
	 * 确定其只有一个在运行
	 *
	 */

	if(already_running()){
		syslog(LOG_ERR,"daemon already running");
		exit(1);
	}
	/**
	 * 恢复SIGHUP 默认,堵塞其他信号
	 */
	sa.sa_handler=SIG_DFL;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags=0;
	if(sigaction(SIGHUP,&sa,NULL)<0){
		err_quit("%s:can't restore SIGHUP default");
	}
	sigfillset(&mask);
	if((err=pthread_sigmask(SIG_BLOCK,&mask,NULL))!=0){
		err_exit(err,"SIG_BLOCK error");
	}
	/**
	 * 有一个线程负责处理SIGHUP和SIGTERM
	 * 但是实际上他也接受所有的信号
	 */
	err=pthread_create(&tid,NULL,thr_fn,0);
	if(err!=0){
		err_exit(err,"can't create thread");
	}
	/**
	 * 处理其他的对守护线程的初始化
	 */
	exit(0);
}

程序清单 13-4 守护进程重读配置文件的另一种方式

/**
 * 程序清单 13-4 守护进程重读配置文件的另一种方式 P352
 * zy:
 * 不用多线程也可以完成
 */
#include <syslog.h>		//功能:记录至系统记录。
#include <errno.h>
#include <error.c>
#include "apue.h"

extern int already_running(void);

void reread(void){
	/*....*/
}
void sigterm(int signo){
	syslog(LOG_INFO,"got SIGTERM; exiting");
	exit(0);
}

void sighup(int signo){
	syslog(LOG_INFO,"Re-reading configuration file");
	reread();
}
void *thr_fn(void *arg){
	int err,signo;
	err=sigwait(&mask,&signo);
	for(;;){
		if(err!=0){
				syslog(LOG_ERR,"sigwait failed");
				exit(1);
			}
			switch (signo) {
				case SIGHUP:
					syslog(LOG_INFO,"RE-reading configuration file");
					reread();
					break;
				case SIGTERM:
					syslog(LOG_INFO,"got SIGTERM; exiting");
					break;
				default:
					syslog(LOG_INFO,"unexpected signal %d \n",signo);
					break;
			}
	}
	return 0;
}

int main(int argc,char *argv[]){
	char *cmd;
	struct sigaction sa;

	//下面这个if就是想拿到我们给守护线程取得名字
	if((cmd=strrchr(argv[0],'/'))==NULL){//查找一个字符c在另一个字符串str中末次出现的位置
		cmd=argv[0];
	}else{
		cmd++;
	}

	daemonize(cmd);

	/*
	 * 确定其只有一个在运行
	 */

	if(already_running()){
		syslog(LOG_ERR,"daemon already running");
		exit(1);
	}

	sa.sa_handler=sigterm;
	sigemptyset(&sa.sa_mask);
	sigaddset(&sa.sa_mask,SIGHUP); //处理SIGTERM的时候会堵塞这个信号SIGHUP
	sa.sa_flags=0;

	if(sigaction(SIGTERM,&sa,NULL)<0){
		syslog(LOG_ERR,"can't catch SIGHUP:%s",strerror(errno));
		exit(1);
	}
	sa.sa_handler=sighup;
	sigemptyset(&sa.sa_mask);
	sigaddset(&sa.sa_mask,SIGTERM); //处理SIGTERM的时候会堵塞这个信号SIGHUP
	sa.sa_flags=0;

	if(sigaction(SIGHUP,&sa,NULL)<0){
		syslog(LOG_ERR,"can't catch SIGHUP:%s",strerror(errno));
		exit(1);
	}


	/**
	 * 其他代码
	 */
	exit(0);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值