UNIX高级环境编程读书笔记(chapter13)
来源:互联网 发布:携程亲子园 知乎 编辑:程序博客网 时间:2024/06/09 23:04
第十三章 守护进程
守护进程也称精灵进程是生存期较长的一种进程,它们常常在系统自举时启动,关闭时才终止,因为它们没有控制终端,所以说它们是在后台运行的。
系统进程依赖于操作系统实现。父进程ID为0的进程通常是内核进程,它们作为系统自举过程的一部分而启动。
一、编程规则
在编写守护进程程序时需遵循一些基本规则,以便防止产生并不需要的交互作用:
(1)首先要做的是调用umask将文件模式创建屏蔽字设置为0。由继承得来的文件模式创建屏蔽字可能会拒绝设置 某些权限。
(2)调用fork,然后使父进程退出。
(3)调用setsid以创建一个新会话。
(4)将当前工作目录更改为新目录。
(5)关闭不在需要的文件描述符。
(6)
实例:初始化一个守护进程
#include "apue.h"#include <syslog.h>#include <fcntl.h>#include <sys/resource.h>voiddaemonize(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); } 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 (rl.rlim_max == RLIM_INFINITY) { rl.rlim_max = 1024; } for (i = 0; i < rl.rlim_max; i++) { close(i); } fd0 = open("/dev/null", O_RDWR); fd1 = dup(0); fd2 = dup(0); openlog(cmd, LOG_CONS, LOG_DAEMON); if (fd0 != 0 || fd1 != 1 || fd2 != 2) { syslog(LOG_ERR, "unexpected file descriptors %d %d %d", fd0, fd1, fd2); exit(1); }}
二、出错记录
有三种方法产生日志消息:
(1)内核例程可以调用log函数。
(2)大多数用户进程(守护进程)调用syslog(3)函数以产生日志信息。
(3)在此主机上的一个用户进程,或通过TCP/IP网络链接到此主机的其它主机上的一个用户进程可将日志消息发向UDP端口514.
void openlog(const char *ident, int option, int facility);
void syslog(int priority , const char *format, ...);
void closelog(void);
int setlogmask(int maskpri);
调用openlog是可选择的。如果不调用openlog,则在第一次调用syslog时, 自动调用openlog。调用closelog也是可选择的——它只是关闭曾被用于与syslog守护进程通信的描述符。
调用syslog产生一个日志消息。
setlogmask函数用于设置进程的记录优先级屏蔽字。
三、单实例守护进程
为了正常运作,某些守护进程实现为单实例的,也就是在任一时刻只运行该守护进程的一个副本。
文件锁和记录锁机制是一种方法的基础,该方法用来保护一个守护进程只有一个副本在运行。
文件锁个记录锁提供了一种方便的互斥机制。如果守护进程在整个文件上得到一把写锁,那么在该守护进程终止时,这把锁将被自动删除,这就简化了复原所需的处理,去除了对以前守护进程实例需要进行清理的有关操作。
实例:保证只运行某个守护进程的一个副本
#include <unistd.h>#include <stdlib.h>#include <fcntl.h>#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);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);}
四、守护进程的惯例
1.若守护进程使用锁文件,那么该文件通常存放在/var/run目录中。
2.若守护进程支持配置选项,那么配置文件通常放在/etc目录中。
3.守护进程可用命令行启动,但通常它们是由系统初始化脚本之一(/etc/rc* 或 /etc/init.d/*)启动的。
4.若一守护进程有一配置文件,那么当该守护进程启动时,它读改文件,但在此后一般就不会再查看它.
实例:守护进程重读配置文件
#include "apue.h"#include <pthread.h>#include <syslog.h>#include <unistd.h>#include <stdlib.h>#include <fcntl.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);static int already_running(void);sigset_t mask;voidreread(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 configuratttion file"); reread(); break; case SIGTERM: syslog(LOG_INFO, "got SIGTERM; exiting"); exit(0); default: syslog(LOG_INFO, "unexpected signal %d\n", signo); } } return(0);}intmain(int argc, char *argv[]){ int err; pthread_t tid; char *cmd; struct sigaction sa; if (cmd = strrchr(argv[0], '/') == NULL) { cmd = argv[0]; } else { cmd++; } daemonize(cmd); if (alreadyrunning()) { syslog(LOG_ERR, "daemon already running"); exit(1); } sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGHUP, &sa, NULL) < 0) { err_quit("%s: can't reatore SIGHUP default"); } sigfillset(&mask); if ((err = pthread_sigmask(SIG_BLOCK, &mask, NULL)) != 0) { err_exit(err, "SIG_BLOCK error"); } err = pthread_create(&tid, NULL, thr_fn, 0); if (err != 0) { err_exit(err, "can't create thread"); } exit(0);}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);}
实例:守护进程重读配置文件的另一种实现
#include "apue.h"#include <pthread.h>#include <syslog.h>#include <unistd.h>#include <stdlib.h>#include <fcntl.h>#include <string.h>#include <errno.h>#include <stdio.h>#include <sys/stat.h>extern int lockfile(int);static int already_running(void);voidreread(void){}voidsigterm(int signo){ syslog(LOG_INFO, "got SIGTERM; exiting"); exit(0);}voidsighup(int signo){ syslog(LOG_INFO, "Re-reading configuration file"); reread();}intmain(int argc, char *argv[]){ char *cmd; struct sigaction sa; if (cmd = strrchr(argv[0], '/') == NULL) { cmd = argv[0]; } else { cmd++; } daemonize(cmd); if (alreadyrunning()) { syslog(LOG_ERR, "daemon already running"); exit(1); } sa.sa_handler = sigterm; sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGHUP); sa.sa_flags = 0; if (sigaction(SIGTERM, &sa, NULL) < 0) { err_quit(LOG_ERR, "can't catch SIGTERM: %s", strerron(errno)); exit(1); } sa.sa_handler = sighup; sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGTERM); sa.sa_flags = 0; if (sigaction(SIGHUP, &sa, NULL) < 0) { err_quit(LOG_ERR, "can't catch SIGHUP: %s", strerron(errno)); exit(1); } exit(0);}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);}
- UNIX高级环境编程读书笔记(chapter13)
- 《Unix环境高级编程》读书笔记(1)
- Unix环境高级编程读书笔记(一)
- UNIX高级环境编程读书笔记(chapter4)
- UNIX高级环境编程读书笔记(chapter5)
- UNIX高级环境编程读书笔记(chapter7)
- UNIX高级环境编程读书笔记(chapter8)
- UNIX高级环境编程读书笔记(chapter9)
- UNIX高级环境编程读书笔记(chapter10)
- UNIX高级环境编程读书笔记(chapter11)
- UNIX高级环境编程读书笔记(chapter12)
- UNIX高级环境编程读书笔记(chapter14)
- 《unix环境高级编程》 读书笔记 (1)
- 《unix环境高级编程》 读书笔记 (2)
- 《unix环境高级编程》 读书笔记 (3)
- 《unix环境高级编程》 读书笔记 (4)
- 《unix环境高级编程》 读书笔记 (5)
- 《unix环境高级编程》 读书笔记 (6)
- servlet总结
- python MySQLdb安装和使用
- Linux下Socket编程
- LeetCode Pascal's Triangle II
- JAVA简单练习(一)
- UNIX高级环境编程读书笔记(chapter13)
- Xcode 打包 ipa 包
- smtp发邮件实现及邮件发送时的一些报错问题的解决
- Java中final修饰参数的作用之一
- Java软件开发基础知识梳理之(5)------Hibernate N + 1产生原因及解决办法
- 使用ptrace跟踪进程
- jsp内置9个对象
- ajax提交异步验证
- expdp\impdp及exp\imp