专栏首页热爱ITpython中的daemon守护进程实现方法[python2.6]

python中的daemon守护进程实现方法[python2.6]

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

守护进程的特性 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-8 #description: 一个守护进程的简单包装类, 具备常用的start|stop|restart|status功能, 使用方便 #             需要改造为守护进程的程序只需要重写基类的run函数就可以了 #date: 2015-10-29 #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=022, verbose=1):         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 > 0:                 sys.exit(0)         except OSError, e:             sys.stderr.write('fork #1 failed: %d (%s)\n' % (e.errno, e.strerror))             sys.exit(1)         os.chdir(self.home_dir)         os.setsid()         os.umask(self.umask)         try:             pid = os.fork()             if pid > 0:                 sys.exit(0)         except OSError, e:             sys.stderr.write('fork #2 failed: %d (%s)\n' % (e.errno, e.strerror))             sys.exit(1)         sys.stdout.flush()         sys.stderr.flush()         si = file(self.stdin, 'r')         so = file(self.stdout, 'a+')         if self.stderr:             se = file(self.stderr, 'a+', 0)         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 >= 1:             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 >= 1:             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(1)         #start the daemon         self.daemonize()         self.run(*args, **kwargs)     def stop(self):         if self.verbose >= 1:             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 = 0             while 1:                 os.kill(pid, signal.SIGTERM)                 time.sleep(0.1)                 i = i + 1                 if i % 10 == 0:                     os.kill(pid, signal.SIGHUP)         except OSError, err:             err = str(err)             if err.find('No such process') > 0:                 if os.path.exists(self.pidfile):                     os.remove(self.pidfile)             else:                 print str(err)                 sys.exit(1)             if self.verbose >= 1:                 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=022, verbose=1):         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(1)         fd.close() if __name__ == '__main__':     help_msg = 'Usage: python %s <start|stop|restart|status>' % sys.argv[0]     if len(sys.argv) != 2:         print help_msg         sys.exit(1)     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=1)     if sys.argv[1] == 'start':         cD.start(log_fn)     elif sys.argv[1] == 'stop':         cD.stop()     elif sys.argv[1] == 'restart':         cD.restart(log_fn)     elif sys.argv[1] == '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://zhidao.baidu.com/link?url=3oGf3-g9x9tlR-VrYaG-hc8HiyXxKQznCXBe1C7M4rxzbbbOokOHkYi-VV9mcZ5dvljekexegBolO-5MCSyUpXp3Uv4--7-5GNDBLSqqD0S 很有参考价值 http://blog.csdn.net/mr_jj_lian/article/details/7252222 原理讲解非常到位 http://www.jb51.net/article/54199.htm 都不错,这个守护进程类包装非常完备,我已经重新整理了一遍

(adsbygoogle = window.adsbygoogle || []).push({});

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 如何在php后端及时推送消息给客户端 转

    walkor大神,目前需求是这样的: 有一群商家在后台网页处理批量导入产品 -》 服务器接受请求 -》 开始foreach一个一个处理...

    双面人
  • 用docker建主机的几个要点 原

    docker run --privileged=true --dns=192.168.1.1 --name shop-t -d -p 8080:80 -v /p...

    双面人
  • js委托事件 转

    document.getElementById("spec_area").addEventListener("click",function(e) {   /...

    双面人
  • Weex 事件传递的那些事儿

    在前两篇文章里面分别谈了Weex如何在Native端初始化的和Weex是如何高效的渲染Native的原生UI的。Native这边还缺一块,那就是Native产生...

    一缕殇流化隐半边冰霜
  • [Python]获取起点小说网的更新情况

    原文链接:https://blog.csdn.net/humanking7/article/details/90176191

    祥知道
  • Python多线程(四)

    如何使用线程本地数据 实际案例: 实现了一个web视频监控服务器,服务端采集摄像头数据,客户端使用浏览器通过http请求接收数据,服务器使用推送的方式(mult...

    企鹅号小编
  • 如何用100行Python代码做出魔性声控游戏“八分音符酱”

    最近几天,一款魔性的小游戏在微博上刷屏了,各大平台的主播也纷纷如感染病毒一样直播自己怎么玩这个游戏(被游戏玩)。 这个游戏叫做《不要停!八分音符酱♪》。它是一款...

    Crossin先生
  • 图像处理: 超像素(superpixels)分割 SLIC算法

    超像素概念是2003年Xiaofeng Ren提出和发展起来的图像分割技术,是指具有相似纹理、颜色、亮度等特征的相邻像素构成的有一定视觉意义的不规则像素块。它利...

    JNingWei
  • python 类支持with调用

    为了让一个对象兼容 with 语句,你需要实现 __enter__() 和 __exit__() 方法。 例如,考虑如下的一个类,它能为我们创建一个网络连接:

    用户5760343
  • ARKit中控制.dae动画的播放

    4.用时间控制动画--CAAnimation 里的 timeOffset 控制开始时间 duration控制播放时间

扫码关注云+社区

领取腾讯云代金券