Python守护进程

Python守护进程

  

 守护进程最重要的特性是后台运行;它必须与其运行前的环境隔离开来,这些环境包括未关闭的文件描述符、控制终端、会话和进程组、工作目录以及文件创建掩码等;它可以在系统启动时从启动脚本/etc/rc.d中启动,可以由inetd守护进程启动,也可以有作业规划进程crond启动,还可以由用户终端(通常是shell)执行。
       Python有时需要保证只运行一个脚本实例,以避免数据的冲突。 

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# from: https://www.cnblogs.com/jiangzhaowei/p/6591106.html 适当修改
'''
功能:将当前进程fork称为一个守护进程
注意:如果你的守护进程是由inetd启动的,不要这样做!inetd完成了,只需要os.chdir 和os.unmask了
'''

import sys,os


def daemonize(stdin='/dev/null',stdout='/dev/null',stderr='/dev/null'):
    #重定向文件描述符,默认情况下定向到/dev/null
    #1、第一次fork
    try:
        fork_result = os.fork()
        if fork_result > 0 :#说明fork成功,当前进程执行if里面代码,即:结束当前进程,整个代码块继续以子进程身份向下进行运行
            sys.exit(0)
    except OSError  as e:
        sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno,e.strerror))#fork失败直接退出
        sys.exit(1)
    #至此没有报错说明到这里已经在第一层子进程中运行,父进程已经退出了,这意味着一个非会话组头领进程永远不能重新获得控制终端。

    #从母体环境脱离
    os.chdir('/')   #chdir 确认进程不保持任何目录于使用状态,否则不能umount一个文件系统。也可以改变到对于守护进程运行重要文件所在目录
    os.umask(0)     #调用umask(0) 以后便拥有对于任何东西的完全控制,因为有时不知道继承了什么样的umask
    os.setsid()     #调用setid()成功后,进程称为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离

    #2、第二次执行fork
    try:
        pid = os.fork()
        if pid > 0:
            sys.exit(0)
    except OSError as e:
        sys.stderr.write('fork #2 failed :%d %s\n'% (e.errno,e.strerror))
        sys.exit(1)

    #到此处进程已经是守护进程了,重定向文件描述符
    for f in sys.stdout,sys.stderr:
        f.flush()
    si = open(stdin,'r')
    so = open(stdout,'ab+')
    se = open(stderr,'ab+',0) #如果 buffering 的值被设为 0,就不会有寄存。

    os.dup2(si.fileno(),sys.stdin.fileno())# dup2函数原子化关闭和复制文件描述符,
    os.dup2(so.fileno(),sys.stdout.fileno())
    os.dup2(se.fileno(),sys.stderr.fileno())
    #截止此处,文件标准输入,标准输出,标准错误文件描述符得指向位置都被更改为指向具体打开的文件

#做一个示例函数在后台进程中测试使用
def main():
    import time
    sys.stdout.write('Daemon started with pid %d\n' % os.getpid())
    sys.stdout.write('Daemon stdout output \n' )
    sys.stderr.write('Daemon stderr output \n' )
    c = 0
    while True:
        sys.stdout.write('%d %s\n' % (c,time.ctime()))
        sys.stdout.flush()
        c += 1
        time.sleep(1)
if __name__ == "__main__":
    daemonize('/dev/null','/tmp/daemon_stdout','/tmp/daemon_stderr')
    main()

 

posted on 2019-10-22 20:04  zhangmingda  阅读(288)  评论(0编辑  收藏  举报

导航