原文参考:http://blog.csdn.net/tao_627/article/details/49532021

守护进程是生存期长的一种进程。它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。他们常常在系统引导装入时启动,在系统关闭时终止。

守护进程的特性
1.在后台运行
2.与其运行前的环境隔离开来。这些环境包括未关闭的文件描述符、控制终端、会话和进程组、工作目录以及文件创建掩码等。这些环境通常是守护进程从执行它的父进程(特别是shell)中继承下来的。
3.启动方式特殊,它可以在系统启动时从启动脚本/etc/rc.d中启动,可以由inetd守护进程启动,可以由crond启动,还可以由用户终端(通常是shell)执行。
总之,除开这些特殊性以外,守护进程与普通进程基本上没有什么区别。因此,编写守护进程实际上是把一个普通进程按照上述的守护进程的特性改造成为守护进程。

守护进程编程规则
1.在后台运行,调用fork ,然后使父进程exit
2.脱离控制终端,登录会话和进程组,调用setsid()使进程成为会话组长
3.禁止进程重新打开控制终端
4.关闭打开的文件描述符,调用fclose()
5.将当前工作目录更改为根目录。
6.重设文件创建掩码为0
7.处理SIGCHLD 信号

下面是一个的demo源码示例:

#!/usr/bin/env python
#encoding: utf-
#description: 一个守护进程的简单包装类, 具备常用的start|stop|restart|status功能, 使用方便
# 需要改造为守护进程的程序只需要重写基类的run函数就可以了
#date: --
#usage: 启动: python daemon_class.py start
# 关闭: python daemon_class.py stop
# 状态: python daemon_class.py status
# 重启: python daemon_class.py restart
# 查看: ps -axj | grep daemon_class import atexit, os, sys, time, signal class CDaemon:
'''
a generic daemon class.
usage: subclass the CDaemon class and override the run() method
stderr 表示错误日志文件绝对路径, 收集启动过程中的错误日志
verbose 表示将启动运行过程中的异常错误信息打印到终端,便于调试,建议非调试模式下关闭, 默认为1, 表示开启
save_path 表示守护进程pid文件的绝对路径
'''
def __init__(self, save_path, stdin=os.devnull, stdout=os.devnull, stderr=os.devnull, home_dir='.', umask=, verbose=):
self.stdin = stdin
self.stdout = stdout
self.stderr = stderr
self.pidfile = save_path #pid文件绝对路径
self.home_dir = home_dir
self.verbose = verbose #调试开关
self.umask = umask
self.daemon_alive = True def daemonize(self):
try:
pid = os.fork()
if pid > :
sys.exit()
except OSError, e:
sys.stderr.write('fork #1 failed: %d (%s)\n' % (e.errno, e.strerror))
sys.exit() os.chdir(self.home_dir)
os.setsid()
os.umask(self.umask) try:
pid = os.fork()
if pid > :
sys.exit()
except OSError, e:
sys.stderr.write('fork #2 failed: %d (%s)\n' % (e.errno, e.strerror))
sys.exit() sys.stdout.flush()
sys.stderr.flush() si = file(self.stdin, 'r')
so = file(self.stdout, 'a+')
if self.stderr:
se = file(self.stderr, 'a+', )
else:
se = so os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno()) def sig_handler(signum, frame):
self.daemon_alive = False
signal.signal(signal.SIGTERM, sig_handler)
signal.signal(signal.SIGINT, sig_handler) if self.verbose >= :
print 'daemon process started ...' atexit.register(self.del_pid)
pid = str(os.getpid())
file(self.pidfile, 'w+').write('%s\n' % pid) def get_pid(self):
try:
pf = file(self.pidfile, 'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None
except SystemExit:
pid = None
return pid def del_pid(self):
if os.path.exists(self.pidfile):
os.remove(self.pidfile) def start(self, *args, **kwargs):
if self.verbose >= :
print 'ready to starting ......'
#check for a pid file to see if the daemon already runs
pid = self.get_pid()
if pid:
msg = 'pid file %s already exists, is it already running?\n'
sys.stderr.write(msg % self.pidfile)
sys.exit()
#start the daemon
self.daemonize()
self.run(*args, **kwargs) def stop(self):
if self.verbose >= :
print 'stopping ...'
pid = self.get_pid()
if not pid:
msg = 'pid file [%s] does not exist. Not running?\n' % self.pidfile
sys.stderr.write(msg)
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
return
#try to kill the daemon process
try:
i =
while :
os.kill(pid, signal.SIGTERM)
time.sleep(0.1)
i = i +
if i % == :
os.kill(pid, signal.SIGHUP)
except OSError, err:
err = str(err)
if err.find('No such process') > :
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
else:
print str(err)
sys.exit()
if self.verbose >= :
print 'Stopped!' def restart(self, *args, **kwargs):
self.stop()
self.start(*args, **kwargs) def is_running(self):
pid = self.get_pid()
#print(pid)
return pid and os.path.exists('/proc/%d' % pid) def run(self, *args, **kwargs):
'NOTE: override the method in subclass'
print 'base class run()' class ClientDaemon(CDaemon):
def __init__(self, name, save_path, stdin=os.devnull, stdout=os.devnull, stderr=os.devnull, home_dir='.', umask=, verbose=):
CDaemon.__init__(self, save_path, stdin, stdout, stderr, home_dir, umask, verbose)
self.name = name #派生守护进程类的名称 def run(self, output_fn, **kwargs):
fd = open(output_fn, 'w')
while True:
line = time.ctime() + '\n'
fd.write(line)
fd.flush()
time.sleep()
fd.close() if __name__ == '__main__':
help_msg = 'Usage: python %s <start|stop|restart|status>' % sys.argv[]
if len(sys.argv) != :
print help_msg
sys.exit()
p_name = 'clientd' #守护进程名称
pid_fn = '/tmp/daemon_class.pid' #守护进程pid文件的绝对路径
log_fn = '/tmp/daemon_class.log' #守护进程日志文件的绝对路径
err_fn = '/tmp/daemon_class.err.log' #守护进程启动过程中的错误日志,内部出错能从这里看到
cD = ClientDaemon(p_name, pid_fn, stderr=err_fn, verbose=) if sys.argv[] == 'start':
cD.start(log_fn)
elif sys.argv[] == 'stop':
cD.stop()
elif sys.argv[] == 'restart':
cD.restart(log_fn)
elif sys.argv[] == 'status':
alive = cD.is_running()
if alive:
print 'process [%s] is running ......' % cD.get_pid()
else:
print 'daemon process [%s] stopped' %cD.name
else:
print 'invalid argument!'
print help_msg

下面是运行截图

产生的日志文件为

参考文档
http://www.jb51.net/article/54199.htm 都不错,这个守护进程类包装非常完备,我已经重新整理了一遍
 

python中的daemon守护进程实现方法的更多相关文章

  1. Python中的线程和进程

    引入进程和线程的概念及区别 threading模块提供的类:   Thread, Lock, Rlock, Condition, [Bounded]Semaphore, Event, Timer, l ...

  2. python实现Linux启动守护进程

    python实现Linux启动守护进程 DaemonClass.py代码: #/usr/bin/env python # -*- coding: utf-8 -*- import sys import ...

  3. nohup命令、setsid命令、Daemon(守护进程)简要梳理

    nohup命令 当用户注销(logout)或者网络断开时,终端会收到 HUP(hangup)信号从而关闭其所有子进程.因此,我们的解决办法就有两种途径:要么让进程忽略 HUP 信号,要么让进程运行在新 ...

  4. python中执行shell的两种方法总结

    这篇文章主要介绍了python中执行shell的两种方法,有两种方法可以在Python中执行SHELL程序,方法一是使用Python的commands包,方法二则是使用subprocess包,这两个包 ...

  5. Python中异步协程的使用方法介绍

    1. 前言 在执行一些 IO 密集型任务的时候,程序常常会因为等待 IO 而阻塞.比如在网络爬虫中,如果我们使用 requests 库来进行请求的话,如果网站响应速度过慢,程序一直在等待网站响应,最后 ...

  6. 举例详解Python中的split()函数的使用方法

    这篇文章主要介绍了举例详解Python中的split()函数的使用方法,split()函数的使用是Python学习当中的基础知识,通常用于将字符串切片并转换为列表,需要的朋友可以参考下   函数:sp ...

  7. Python中os和shutil模块实用方法集…

    Python中os和shutil模块实用方法集锦 类型:转载 时间:2014-05-13 这篇文章主要介绍了Python中os和shutil模块实用方法集锦,需要的朋友可以参考下 复制代码代码如下: ...

  8. Python中os和shutil模块实用方法集锦

    Python中os和shutil模块实用方法集锦 类型:转载 时间:2014-05-13 这篇文章主要介绍了Python中os和shutil模块实用方法集锦,需要的朋友可以参考下 复制代码代码如下: ...

  9. Python中的str与unicode处理方法

    Python中的str与unicode处理方法 2015/03/25 · 基础知识 · 3 评论· Python 分享到:42 原文出处: liuaiqi627 的博客    python2.x中处理 ...

随机推荐

  1. Golang glog使用详解

    golang/glog 是 C++ 版本 google/glog 的 Go 版本实现,基本实现了原生 glog 的日志格式.在 Kuberntes 中,glog 是默认日志库. glog 的使用与特性 ...

  2. 01_13_Struts_默认Action

    01_13_Struts_默认Action 1. 配置struts默认Action <package name="default" namespace="/&quo ...

  3. 理解JS闭包的几个小实验

    学了JavaScript有一段时间了,但是对闭包还是不太理解,于是怀着心中的疑问做了几个小实验,终于有点明白了. 首先看一下MDN上的定义:闭包是函数和声明该函数的词法环境的组合. 简单来说,闭包是一 ...

  4. 2019.5.18-5.19 ACM-ICPC 全国邀请赛(西安)赛后总结

    第一次出去比赛经验太少了!!!果然最大目的是长见识和受刺激Orz 以下流水账: 背了本两千两百页的牛津高阶英汉双解词典,背了吃的,背了衣服……以后这些东西统统不带,买本口袋词典即可.上述物品这次比赛全 ...

  5. python入门:模拟简单用户登录(自写)

    #!/usr/bin/env python # -*- coding: utf-8 -*- #模拟简单用户登录(自写) import getpass a = raw_input("Pleas ...

  6. nginx url rewrite break和last的区别

    break 将重写的URI作为一个新的URI,在本块中继续处理,将重写后 的地址在当前location块中处理,不会将新的URI转向到其他location块中 last,终止继续在本location块 ...

  7. 浅探webpack优化

    由于前端的快速发展,相关工具的发展速度也是相当迅猛,各大框架例如vue,react都有自己优秀的脚手架工具来帮助我们快速启动一个新项目,也正式因为这个原因,我们对于脚手架中最关键的一环webpack相 ...

  8. [译]The Python Tutorial#8. Errors and Exceptions

    [译]The Python Tutorial#Errors and Exceptions 到现在为止都没有过多介绍错误信息,但是已经在一些示例中使用过错误信息.Python至少有两种类型的错误:语法错 ...

  9. Primer C++第五版 读书笔记(一)

    Primer C++第五版 读书笔记(一) (如有侵权请通知本人,将第一时间删文) 1.1-2.2 章节 关于C++变量初始化: 初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义 ...

  10. LeetCode(129) Sum Root to Leaf Numbers

    题目 Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a num ...