《APUE》读书笔记第十三章-守护进程
守护进程
守护进程是生存期较长的一种进程,它们常常在系统自举时启动,仅在系统关闭时才终止。因为它们没有控制终端,所以说它们是在后台运行的。UNIX系统由很多守护进程,它们执行日常事务活动.
本章主要介绍守护进程的结构,以及如何编写守护进程程序和守护进程如何报告错误情况.
一.守护进程的编程规则
(1)首先要做的是调用umask将文件模式创建屏蔽字设置为0.这是由于继承得来的文件模式创建屏蔽字可能会拒绝设置某些权限。
(2)调用fork,然后使父进程退出(exit).
(3)调用setsid以创建一个新会话,使调用进程:(a)成为新会话的首进程,(b)成为一个新进程组的组成进程,(c)没有控制终端。
(4)将当前工作目录更改为根目录。
(4)关闭不需要的文件描述符.这使守护进程不再持有从其父进程继承得来的某些文件描述符
(5)某些守护进程打开/dev/null使其具有文件描述符0、1和2,这样任何一个试图读标准输入、写标准输出或标准出错的库例程都不会产生任何效果.
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/resource.h>
void daemonize(const char* cmd){
int i,fd0,fd1,fd2;
pid_t pid;
struct rlimit r1;
struct sigaction sa; umask();
if(getrlimit(RLIMIT_NOFILE,&r1)<){
printf("%s: can't get file limit",cmd);
exit(-);
} if((pid=fork())<){
printf("%s:can't fork",cmd);
exit(-);
} else if(pid!=){ //parent
exit();
} setsid(); /*
ensure a session leader to lose controlling TTY.
*/
sa.sa_handler=SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags=;
if(sigaction(SIGHUP,&sa,NULL)<){
printf("%s:can't ignore SIGHUP");
exit(-);
}
if((pid=fork())<){
printf("%s:can't ignore SIGHUP");
exit(-);
}
else if(pid!=) exit(); if(chdir("/")<){
printf("can't change directory to/");
exit(-);
} if(r1.rlim_max==RLIM_INFINITY){
r1.rlim_max=;
} for(i=;i<r1.rlim_max;i++) close(i); fd0=open("/dev/null",O_RDWR);
fd1=dup();
fd2=dup(); openlog(cmd,LOG_CONS,LOG_DAEMON);
if(fd0!= || fd1!= || fd2!=){
syslog(LOG_ERR,"unexpected file description %d %d %d",fd0,fd1,fd2);
exit();
}
}
二.出错记录
有三种方法产生日志消息:
(1)内核例程可以调用log函数。任何一个用户进程用过open(打开)然后读(read)/dev/klog设备就可以读取这些消息。
(2)大多数守护进程调用syslog函数以产生日志消息.
(3)在此主机上的一个用户进程,或通过调用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 maskpri);
//返回值:前日志记录优先级屏蔽值
三.单实例守护进程
为了正常运作,某些守护进程实现为单实例的,也就是任一时刻只运行该守护进程的一个副本。文件锁和记录锁是一种方法的基础,该方法用来保证一个守护进程只有一个副本在运行,它们提供了一种互斥机制。如果守护进程在整个文件上得到一把写锁,那么在该守护进程终止时,这把锁将被自动删除.
- 若守护进程使用锁文件,那么该文件通常存放在/var/run目录中。锁文件的名字通常是name.pid,其中,name是该守护进程或服务的名字.例如,cron守护进程锁文件的名是/var/run/crond.pid.
- 若守护进程支持配置选项,那么配置文件通常存放在/etc目录中,配置文件的名字通常是name.conf,其中,name是守护进程或服务的名字.
- 守护进程可以用命令行启动,当通常是由系统初始化脚本之一(/etc/rc*或/etc/init.d/*)启动的.
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h> sigset_t mask;
extern int already_running(void); void reread(void){
/..../
} void* thr_fn(void* arg){
int err,signo; for(;;){
err=sigwait(&mask,&signo);
if(err!=){
syslog(LOG_ERR,"sigwait failed");
exit();
} switch(signo){
case SIGHUP:
syslog(LOG_INFO,"Re-reading configuration file!");
reread();
break; case SIGTERM:
syslog(LOG_INFO,"got SIGTERM exiting");
exit(); default:
syslog(LOG_INFO,"unexpected signal %d\n",signo);
}
}
return ();
} int main(int argc,char* argv[]){
int err;
pthread_t tid;
char *cmd;
struct sigaction sa; if((cmd=strchr(argv[],'/'))==NULL){
cmd=argv[];
}
else cmd++; /*
*Become a daemon
*/
daemonize(cmd); if(already_running()){
syslog(LOG_ERR,"daemon already running");
exit();
} sa.sa_handler=SIG_DFL;
sigemptyset(&sa.sa_mask);
sa.sa_flags=; if(sigaction(SIGHUP,&sa,NULL)<){
err_printf("%s: can't restore SIGHUP default");
} sigfillset(&mask);
if((err=pthread_sigmask(SIG_BLOCK,&mask,NULL))!=)
err_exit(err,"SIG_BLOCK error"); err=pthread_create(&tid,NULL,thr_fn,);
if(err!=){
err_exit(err,"can't create thread");
} exit(); }
《APUE》读书笔记第十三章-守护进程的更多相关文章
- APUE读书笔记-第13章-守护进程
第13章 守护进程 13.1 引言 *守护进程也称精灵进程(daemon)是生存期较长的一种进程.它们常常在系统自举时启动,仅在系统关闭时才终止.因为它们没有控制终端,所以说它们是在后台运行的.UNI ...
- 《Unix环境高级编程》读书笔记 第13章-守护进程
1. 引言 守护进程是生存期长的一种进程.它们常常在系统引导装入时启动,仅在系统关闭时才终止.它们没有控制终端,在后台运行. 本章说明守护进程结构.如何编写守护进程程序.守护进程如何报告出错情况. 2 ...
- apue学习笔记(第十三章 守护进程)
本章将说明守护进程结构,以及如何编写守护进程程序. 守护进程,也就是通常说的Daemon进程,是Unix中的后台服务进程.它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理 ...
- UNP学习笔记(第十三章 守护进程和inetd超级服务器)
关于守护进程可以查看apue的笔记 http://www.cnblogs.com/runnyu/p/4645046.html daemon_init函数 下面给出名为daemon_init函数,通过调 ...
- APUE读书笔记-第17章-高级进程间通信
17.1 引言 *两种高级IPC:基于STREAMS的管道(STREAMS-based pipe)以及UNIX域套接字(UNIX domain socket)可以在进程间传送打开文件描述符.服务进程可 ...
- 《Linux程序设计》--读书笔记---第十三章进程间通信:管道
管道:进程可以通过它交换更有用的数据. 我们通常是把一个进程的输出通过管道连接到另一个进程的输入: 对shell命令来说,命令的连接是通过管道字符来完成的: cmd1 | cmd2 sh ...
- APUE读书笔记-第18章-终端I/O
18.1 引言 *终端I/O的用途很广泛,包括用于终端.计算机之间的直接连线.调制解调器以及打印机等等,所以终端I/O系统非常复杂 18.2 综述 *终端I/O有两种不同的工作模式: (1)规范模式输 ...
- APUE读书笔记-第14章-高级I/O
14.1 引言 *高级I/O包括非阻塞I/O.记录锁.系统V流机制.I/O多路转换(select和poll函数).readv和writev函数以及存储映射I/O(mmap) 14.2 非阻塞I/O * ...
- APUE读书笔记-第15章-进程间通信
15.1 引言 *进程之间交换信息的方法可以经由fork或exec传送打开文件,或者通过文件系统 *进程之间相互通信的其他技术——IPC(InterProcess Communication)包括半双 ...
随机推荐
- MBProgressHUD的基本使用
MBProgressHUD的基本使用 分类: IOS2012-10-30 11:19 12047人阅读 评论(2) 收藏 举报 和gitHub上的Demo其实差不多,就是小整理了下,当备忘,想做复杂的 ...
- Linux里面怎样修改主机名
第一步:hostname 修改后的主机名 第二步:修改/etc/sysconfig/network中的hostname第三步:修改/etc/hosts文件 示例: 我机器现在的主机名是pc,想修改成t ...
- Altium Designer多图纸原理图设计方法探讨
1 图纸结构 包括层次式图纸的连接关系是纵向的,也就是某一层次的图纸只能和相邻的上级或下级有关系,另一种即扁平式图纸的连接关系是横向的,任何两张图纸之间都可以建立信号连接. 2 网络连接方式 Alti ...
- bootstrap 动态添加验证项和取消验证项
bootstrap 中的bootstrapValidator可以对前端的数据进行验证,但是有的时候我们需要动态的添加验证,这样需要我们动态的对bootstrapValidator的内容做修改. 传统的 ...
- 嵌入式linux内核制作
今天来总结一下mini2440的内核制作过程. 一. 将内核文件拷贝至目标目录,解压. 二.清除中间文件 命令:make distclean 三.配置内核文件 将开发板厂商制作好的内核文件拷贝至内核文 ...
- cf500A New Year Transportation
A. New Year Transportation time limit per test 2 seconds memory limit per test 256 megabytes input s ...
- BZOJ 3040 最短路 (堆优化dijkstra)
这题不是裸的最短路么?但是一看数据范围就傻了.点数10^6,边数10^7.这个spfa就别想了(本来spfa就是相当不靠谱的玩意),看来是要用堆优化dijkstra了.但是,平时写dijkstra时为 ...
- 【转】被误解的MVC和被神化的MVVM
被误解的MVC和被神化的MVVM 作者 唐巧 发布于 2015年11月2日 | ArchSummit全球架构师峰会(北京站)2016年12月02-03日举办 被误解的 MVC MVC 的历史 MV ...
- 关于数据表命名为mysql保留的时候的操作
今天操作数据表的时候,发现order数据表无法进行操作,必须加上反单引号才能进行操作,查了一下原因: 反引号是用来区别mysql关键字的,比如,如果你有一个表名叫select,你就必须写成`selec ...
- 性能计数器自动收集-logman
1.在桌面云测试中,往往需要模拟并发连接中服务器的性能数据,这里主要介绍如何自动收集性能数据 2.创建xxxx.bat文件,文件内容如下: logman create counter test -cf ...