linux在python

时间:2016-08-12 14:42:11

标签: python linux python-3.x shutdown

我一直致力于为我作为无头服务器运行的覆盆子pi开发监控脚本。作为其中的一部分,我希望它对关闭事件作出反应。 我尝试使用signal模块,它确实做出了反应并调用了我的关机例程,但它在关机例程发生的很晚才发生,我想尝试找到一种方法让它在很快后做出反应发出关闭请求,而不是等待操作系统要求python退出。

这是在树莓派1 B上运行,使用最新的jessie lite图像 我使用的是python 3,我的python脚本本身就是init脚本:

监视器:

#!/usr/bin/python3
### BEGIN INIT INFO
# Provides:          monitor
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start the monitor daemon
# Description:       Start the monitor daemon during system boot
### END INIT INFO

import os, psutil, socket, sys, time
from daemon import Daemon
from RPLCD import CharLCD
from subprocess import Popen, PIPE
import RPi.GPIO as GPIO

GPIO.setwarnings(False)

def get_cpu_temperature():
    process = Popen(['vcgencmd', 'measure_temp'], stdout=PIPE)
    output, _error = process.communicate()
    output = output.decode('utf8')
    return float(output[output.index('=') + 1:output.rindex("'")])

class MyDaemon(Daemon):
    def run(self):
        lcd = CharLCD(pin_rs=7, pin_rw=4, pin_e=8, pins_data=[25, 24, 23, 18], numbering_mode=GPIO.BCM, cols=40, rows=2, dotsize=8)

        while not self.exitflag:
            gw = os.popen("ip -4 route show default").read().split()
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            try:
                s.connect((gw[2], 0))
                ipaddr = s.getsockname()[0]
                lcd.cursor_pos = (0, 0)
                lcd.write_string("IP:" + ipaddr)
                gateway = gw[2]
                lcd.cursor_pos = (1, 0)
                lcd.write_string("GW:" + gateway)
            except IndexError:
                lcd.cursor_pos = (0, 0)
                lcd.write_string("IP:No Network")
                lcd.cursor_pos = (1, 0)
                lcd.write_string("GW:No Network")

            host = socket.gethostname()
            lcd.cursor_pos = (0, 20)
            lcd.write_string("Host:" + host)

            for num in range(10):
                temp = get_cpu_temperature()
                perc = psutil.cpu_percent()
                lcd.cursor_pos = (1, 20)
                lcd.write_string("CPU :{:5.1f}% {:4.1f}\u00DFC".format(perc, temp))
                if (self.exitflag):
                    break
                time.sleep(2)
        lcd.clear()
##      lcd.cursor_pos = (13, 0)
        lcd.write_string("Shutting Down")

if __name__ == "__main__":
    daemon = MyDaemon('/var/run/monitor.pid')
    if len(sys.argv) == 2:
        if 'start' == sys.argv[1]:
            daemon.start()
        elif 'stop' == sys.argv[1]:
            daemon.stop()
        elif 'restart' == sys.argv[1]:
            daemon.restart()
        elif 'run' == sys.argv[1]:
            daemon.run()
        else:
            print("Unknown command")
            sys.exit(2)
        sys.exit(0)
    else:
        print("usage: %s start|stop|restart" % sys.argv[0])
        sys.exit(2)

daemon.py:

"""Generic linux daemon base class for python 3.x."""

import sys, os, time, signal

class Daemon:
    """A generic daemon class.
    Usage: subclass the daemon class and override the run() method."""
    def __init__(self, pidfile):
        self.pidfile = pidfile
        self.exitflag = False
        signal.signal(signal.SIGINT, self.exit_signal)
        signal.signal(signal.SIGTERM, self.exit_signal)

    def daemonize(self):
        """Deamonize class. UNIX double fork mechanism."""
        try: 
            pid = os.fork() 
            if pid > 0:
                # exit first parent
                sys.exit(0) 
        except OSError as err: 
            sys.stderr.write('fork #1 failed: {0}\n'.format(err))
            sys.exit(1)

        # decouple from parent environment
        os.chdir('/') 
        os.setsid() 
        os.umask(0) 

        # do second fork
        try: 
            pid = os.fork() 
            if pid > 0:

                # exit from second parent
                sys.exit(0) 
        except OSError as err: 
            sys.stderr.write('fork #2 failed: {0}\n'.format(err))
            sys.exit(1) 

        # redirect standard file descriptors
        sys.stdout.flush()
        sys.stderr.flush()
        si = open(os.devnull, 'r')
        so = open(os.devnull, 'a+')
        se = open(os.devnull, 'a+')

        os.dup2(si.fileno(), sys.stdin.fileno())
        os.dup2(so.fileno(), sys.stdout.fileno())
        os.dup2(se.fileno(), sys.stderr.fileno())

        pid = str(os.getpid())
        with open(self.pidfile,'w+') as f:
            f.write(pid + '\n')

    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:
            pid = None

        if pid:
            message = "pidfile {0} already exist. Daemon already running?\n"
            sys.stderr.write(message.format(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:
            pid = None

        if not pid:
            message = "pidfile {0} does not exist. Daemon not running?\n"
            sys.stderr.write(message.format(self.pidfile))
            return # not an error in a restart

        # Try killing the daemon process    
        try:
            while 1:
                os.kill(pid, signal.SIGTERM)
                time.sleep(0.1)
        except OSError as err:
            e = str(err.args)
            if e.find("No such process") > 0:
                if os.path.exists(self.pidfile):
                    os.remove(self.pidfile)
            else:
                print (str(err.args))
                sys.exit(1)

    def restart(self):
        """Restart the daemon."""
        self.stop()
        self.start()

    def exit_signal(self, sig, stack):
        self.exitflag = True
        try:
            os.remove(self.pidfile)
        except FileNotFoundError:
            pass

    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()."""

所以总之有什么方法我可以在关机时尽可能早地检测到关机,无论它如何调用,最好还能从python中检测到重启

1 个答案:

答案 0 :(得分:1)

不要反应。 附表

Unixoid系统在启动和关闭时具有完善的启动和停止服务机制。只需在系统关闭时添加其中一个即可停止;您通常甚至可以定义可以调用这些关闭脚本的顺序。

现在,我不了解您使用Linux的这些系统中的哪一个。您可能正在使用

  • SysV风格的init脚本(经典)
  • systemd(相对较新)
  • 暴发户(如果您正在运行Canonical误导的实验之一)

无论哪种方式,系统上都有很多此类服务文件的例子;如果您正在运行systemd,systemctl将显示当前加载的服务,并显示您应该查看哪些文件进行复制并添加为您自己的服务。如果您正在运行SysV-Style init,请查看/etc/init.d以获取大量脚本。

您将找到有关如何为特定运行级别/系统目标添加和启用init脚本或systemd服务文件的大量信息。