【浅谈守护进程】Demo:后台监控程序-- Python实现
2017-05-24 21:39
597 查看
前言
最近在做的项目需要定期检测某个进程是否运行,若挂了自动重启,脑袋一拍觉得需要这样一个守护进程 来进行监控,于是顺便复习了一下守护进程。正文
什么是守护进程?
守护进程(daemon)是生存期长的一种进程。它们常常在系统引导装入时启动,仅在系统关闭时才终止。因为它们没有控制终端,所以说它们是在后台运行的。—–《APUE》
我们需求就是默默地定期执行任务 与守护进程非常的匹配。
编写一个守护进程
守护进程需要
设置文件模式创建屏蔽字。没有控制终端。
确定工作目录。
关闭不再需要的文件描述符。
告别标准输入输出
如何实现
文件模式屏蔽字
只需要通过umask()即可,由继承(至于为什么是继承,请看后面)得到的文件模式创建屏蔽字可能已经被修改为拒绝某些权限,所以我们最好根据需要进行重新设置。
甩掉控制终端
我们希望守护进程在后台默默运行不受控制终端的控制。这里是通过setsid()函数来实现。调用这个函数的效果是:
1)创建一个新会话(session)
2)创建一个新进程组。
3)调用进程成为 新会话 的首进程
4)调用进程成为 新进程组 的组长进程
5)调用进程失去控制终端
最后一条正是我们需要的效果,但这个函数也有前提条件。那就是调用函数不能是进程组的组长进程,为了达到这个条件,我们通常的做法是,首先调用
fork()然后父进程退出,由子进程来
setsid()。因为,子进程获得的进程组ID和自己的PID必然不同,也就是子进程必然不是进程组的组长进程,可以顺利调用
setsid()。
潜在的BUG
在基于System V的系统如Linux,存在以下的实现当会话首进程打开第一个尚未与一个会话相关联的终端设备时,只要在调用
open()时没有指定
O_NOCTTY标志,那么System V派生的系统将此作为控制终端分配给此会话。 —《APUE》
为了消除这个BUG,我们在通常的做法(先调用
fork()然后父进程退出,由子进程来
setsid())之后,再调用一次
fork(),然后再次让父进程退出,使用子进程,这样子进程不是会话(组)首进程,就消除了这个BUG。
当然也可以在之后每次open终端设备时加上
O_NOCTTY标志。。。。
[b]同时,在glibc中的
daemon()就因为其实现只是
fork()一次,存在这个BUG(来自man) [/b]
确定工作目录
这里主要是因为守护进程其长期工作的特性,如果当前目录为挂载的文件系统,会导致其文件系统不能被卸载。所以我们用chdir()显式地设置工作目录。
关闭不再需要的文件描述符
还是由于fork()继承的原因可能具有不需要一些文件描述符,所以我们要显式的关闭。
告别标准输入输出
。。。其实前面都关了,不过考虑到某些和标准输出输入错误扯上关系的库函数,我们就把0,1,2设置为/dev/null。
Demo:后台监控程序—Python实现
#!/usr/bin/env python # coding=utf-8 # Jack Kang import os import time import sys # 检测port对应节点是否存活 def check(port): isAlive = "ps -ef | grep \"" + port + " \[cluster\]\"" recovery = "redis-server ./" + port + "/redis.conf" if os.system(isAlive): #判断 os.system(recovery) #进程不存在,重启节点 #设置为守护进程 stdin = '/dev/null' stdout = '/dev/null' stderr = '/dev/null' try: pid = os.fork() if pid > 0 : sys.exit(0) except OSError, e: print "error #1" sys.exit(1) os.chdir("./redis_cluster") # 切换工作目录 os.umask(0) # 设置文件模式创建屏蔽字 os.setsid() # 甩掉控制终端 # 第二次fork 保证子进程不是会话首进程 try: pid = os.fork() if pid > 0: sys.exit(0) #父进程退出 except OSError: print "error #2" sys.exit(1) for f in sys.stdout, sys.stderr: f.flush() # 刷新缓冲区 #将标准输出输入错误改为/dev/null si = open(stdin, 'r') so = open(stdout, 'a+') se = open(stderr, 'a+', 0) os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) #主循环 每5s检测port进程是否存活 port = sys.argv[1] while True: check(port) time.sleep(5)
其实C实现和Python很像啦。这里就偷懒不写出C实现了。。。有空补上。
两次fork的结果截图
可以看到pid 不等于sid 所以不是会话首进程
引用及参考
APUE第十三章(守护进程)第九章(进程关系)Demo 中守护进程部分的实现 主要参考了Python实例浅谈之五Python守护进程和脚本单例运行
才疏学浅,不足之处,欢迎指正。
相关文章推荐
- [Python网络编程]浅析守护进程后台任务的设计与实现
- [Python网络编程]浅析守护进程后台任务的设计与实现
- python os.startfile python实现双击运行程序 python监控windows程序 监控进程不在时重新启动
- python编写借助linux中的xinetd守护进程实现我们的网络程序(select、重定向标准输入输出)
- python实现将程序以守护进程的方式运行
- Java 实现程序运行状态监控 之我的思路(守护进程)
- Python实现的守护进程
- 用PHP实现守护进程任务后台运行与多线程(php-resque使用说明)
- 守护进程(简单实现)--程序关闭后自动启动
- 用Python写个进程监控程序
- 用PHP实现守护进程任务后台运行与多线程(php-resque使用说明)
- 用PHP实现守护进程任务后台运行与多线程(php-resque使用说明)
- PHP后台守护进程的实现
- 用PHP实现守护进程任务后台运行与多线程(php-resque使用说明)
- 用PHP实现守护进程任务后台运行与多线程(php-resque使用说明)
- [Python]daemon后台守护进程
- python守护进程监控hive server
- python 写的一个Ice服务端在linux下面的守护进程程序
- python实现后台进程的方法(源码)
- python守护进程监控hive server(类形式)