前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python中的daemon守护进程实现方法[python2.6]

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

作者头像
双面人
发布2019-04-10 14:53:00
7340
发布2019-04-10 14:53:00
举报
文章被收录于专栏:热爱IT热爱IT

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

守护进程的特性 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({});

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档