• python实现Linux启动守护进程


    python实现Linux启动守护进程

    DaemonClass.py代码:

    #/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    import sys
    import os
    import time
    import atexit
    import subprocess
    from signal import SIGTERM
    
    BaseDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    DIRS = {'ROOT': BaseDir,
            'PID': '%s/var/guard.pid' % BaseDir,
            }
    		
    
    class Daemon(object):
        """
        daemon class.
        Usage: subclass the Daemon class and override the _run() method
        """
        def __init__(self, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
            self.stdin = stdin
            self.stdout = stdout
            self.stderr = stderr
            self.pidfile = DIRS['PID']
    
        def _daemonize(self):
            """
            @guard 守护进程主方法
            """
            # 脱离父进程
            try:
                pid = os.fork()
                print("[_daemonize]pid:%s" % pid)
                if pid > 0:
                    sys.exit(0)
            except OSError as e:
                sys.stderr.write("[_daemonize]fork #1 failed: %d (%s)
    " % (e.errno, e.strerror))
                print("[_daemonize]fork #1 failed:"+str(e.strerror))
                sys.exit(1)
    
            # 脱离终端
            os.setsid()
            # 修改当前工作目录
            os.chdir(DIRS['ROOT'])
            # 加载环境变量
            guardpath = DIRS['ROOT']
    
            sys.path.append(guardpath)
            # 重设文件创建权限
            os.umask(0)
    
            # 第二次fork,禁止进程重新打开控制终端
            try:
                pid = os.fork()
                if pid > 0:
                    sys.exit(0)
            except OSError as e:
                sys.stderr.write("[_daemonize]fork #2 failed: %d (%s)
    " % (e.errno, e.strerror))
                print("[_daemonize]fork #2 failed:"+str(e.strerror))
                sys.exit(1)
    
            sys.stdout.flush()
            sys.stderr.flush()
    
            # 重定向文件描述符
            with open(self.stdin, 'rb', 0) as f:
                os.dup2(f.fileno(), sys.stdin.fileno())
            with open(self.stdout, 'ab', 0) as f:
                os.dup2(f.fileno(), sys.stdout.fileno())
            with open(self.stderr, 'ab', 0) as f:
                os.dup2(f.fileno(), sys.stderr.fileno())
    
            # 注册程序退出时的函数,即删掉pid文件
            atexit.register(lambda: os.remove(self.pidfile))
            pid = str(os.getpid())
            file(self.pidfile, 'w+').write("%s
    " % pid)
    
        def start(self):
            """
            Start the daemon
            """
            # Check for a pidfile to see if the daemon already runs
            try:
                with open(self.pidfile, 'r') as pf:
                    pid = int(pf.read().strip())
            except IOError as e:
                pid = None
                print("daemon ioerror :"+str(e))
    
            if pid:
                message = "Start error,pidfile %s already exist. Daemon already running?
    "
                print(message)
                sys.stderr.write(message % self.pidfile)
                sys.exit(1)
    
            # Start the daemon
            self._daemonize()
            self._run()
    
        def stop(self):
            """
            Stop the daemon
            """
            # Get the pid from the pidfile
            try:
                with open(self.pidfile, 'r') as pf:
                    pid = int(pf.read().strip())
            except IOError as err:
                pid = None
                print(err)
    
            if not pid:
                message = "pidfile %s does not exist. Daemon not running?
    " % self.pidfile
                print(message)
                sys.stderr.write(message)
                return  # not an error in a restart
            # Try killing the daemon process
            try:
                while 1:
                    os.kill(pid, SIGTERM)
                    time.sleep(0.1)
            except OSError as err:
                err = str(err)
                if err.find("No such process") > 0:
                    if os.path.exists(self.pidfile):
                        os.remove(self.pidfile)
                else:
                    print('Stop error,'+str(err))
                    sys.exit(1)
    
        def status(self):
            """
            Status the daemon
            """
            # Get the pid from the pidfile
            try:
                with open(self.pidfile, 'r') as pf:
                    pid = int(pf.read().strip())
            except IOError as err:
                pid = None
                print(err)
    
            if not pid:
                message = "pidfile %s does not exist. Daemon not running?
    " % self.pidfile
                print(message)
                sys.stderr.write(message)
            else:
                p = subprocess.Popen('ps -ef|grep %s |grep -v grep' % pid, shell=True,
                                     stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                lines = p.stdout.readlines()
                print(lines)
                if len(lines) > 0:
                    message = "pidfile %s exist. Daemon running!
    " % self.pidfile
                    print(message)
                    sys.stdout.write(message)
                else:
                    message = "pidfile %s exist. But pid not exist, please administrator check process
    " % self.pidfile
                    print(message)
                    sys.stderr.write(message)
    
        def restart(self):
            """
            Restart the daemon
            """
            self.stop()
            time.sleep(0.1)
            self.start()
    
        def _run(self):
            """
            You should override this method when you subclass Daemon. It will be called after the process has been
            daemonized by start() or restart().
            """
            raise NotImplementedError
    

    MainClass.py 继承Daemon类

    #/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    
    import sys
    from DaemonClass import *
    import time
    import subprocess
    
    
    class ArgvHandler(Daemon):
        """
        help_msg: 帮助方法
        parse_argv: 参数检查
        """
    
        def __init__(self, argv_list):
            Daemon.__init__(self)
            self.argvs = argv_list
            print("程序输入参数:%s" % self.argvs)
            self.parse_argv()
    
        def parse_argv(self):
            """
            :return:  获取执行程序后面的参数值,如果没有打印帮助内容
            """
            if len(self.argvs) > 1:
                if hasattr(self, self.argvs[1]):
                    func = getattr(self, self.argvs[1])
                    func()
                else:
                    self.help_msg()
            else:
                self.help_msg()
    
        def help_msg(self):
            print "Unknow Command!"
            print "Usage: %s start|stop|restart|status" % self.argvs[0]
    
        def _run(self):
            """
            监控入口
            """
            MonitorRun()
    
    
    def MonitorRun():
        while 1:
            monitor_process('进程名')
            time.sleep(600)
    
    
    def monitor_process(processname):
        # 进程数量判断
        try:
            p = subprocess.Popen('ps -ef|grep %s |grep -v grep' % processname, shell=True,
                                 stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            lines = p.stdout.readlines()
    
            if len(lines) == 1:
                print("进程名:%s, 数量:%s" % (processname, len(lines)))
                return
            else:
                print("进程名:%s, 数量:%s" % (processname, len(lines)))
                message = 'process[%s] is lost' % (processname)
                print(message)
                return message
        except Exception as err:
            message = "[monitor_process]%s" % err
            print(message)
            sys.stderr.write(message)
    

    启动程序入口

    #/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    
    import os
    import sys
    import platform
    
    if platform.system() == "Windows":
        BASE_DIR = '\'.join(os.path.abspath(os.path.dirname(__file__)).split('\')[:-1])
    else:  # for linux
        BASE_DIR = '/'.join(os.path.abspath(os.path.dirname(__file__)).split('/')[:-1])
    sys.path.append(BASE_DIR)
    
    from lib import MainClass
    
    
    if __name__ == '__main__':
    
        MainClass.ArgvHandler(sys.argv)
    

    参考文档:

    http://blog.csdn.net/taiyang1987912/article/details/44850999

    http://python3-cookbook-zh.readthedocs.io/zh_CN/latest/c12/p14_launching_daemon_process_on_unix.html

  • 相关阅读:
    WPF:DataGrid 自动生成行号
    C#:WinForm之Command
    i.MX RT1010之FlexIO模拟SSI外设
    i.MX RT1010之FlexIO模拟I2S外设
    i.MX RT600之DSP开发环境调试篇
    i.MX RT600之DSP调试环境搭建篇
    i.MX RT600之DMIC外设介绍及应用
    i.MX RT600之I2S外设介绍及应用
    ssm框架思维-登录
    idea里面搭建SSM框架-crud
  • 原文地址:https://www.cnblogs.com/shhnwangjian/p/5918786.html
Copyright © 2020-2023  润新知