<menuitem id="dtdv5"><dl id="dtdv5"><address id="dtdv5"></address></dl></menuitem>
<cite id="dtdv5"><span id="dtdv5"></span></cite>
<del id="dtdv5"><noframes id="dtdv5"><del id="dtdv5"></del>
<ins id="dtdv5"></ins><ins id="dtdv5"></ins>
<ins id="dtdv5"></ins>
<var id="dtdv5"><span id="dtdv5"></span></var>
<del id="dtdv5"><noframes id="dtdv5"><ins id="dtdv5"></ins><del id="dtdv5"></del>
<del id="dtdv5"><noframes id="dtdv5"><ins id="dtdv5"></ins>

概念

守護進程(Daemon)也稱為精靈進程是一種生存期較長的一種進程。它們獨立于控制終端并且周期性的執行某種任務或等待處理某些發生的事件。他們常常在系統引導裝入時啟動,在系統關閉時終止。unix系統有很多守護進程,大多數服務器都是用守護進程實現的,例如inetd守護進程。

需要了解的相關概念

  • 進程 (process)
  • 進程組 (process group)
  • 會話 (session)

可參考以下博文

實現原理

參考 APUE關于守護進程的章節

大致流程如下:

  1. 后臺運行
  1. 脫離控制終端,登錄會話和進程組
  1. 禁止進程重新打開控制終端
  1. 關閉打開的文件描述符
  1. 改變當前工作目錄
  1. 重設umask
  1. 處理SIGCHLD信號
  1. 日志

關于兩次fork

第二個fork不是必須的,只是為了防止進程打開控制終端。

打開一個控制終端的條件是該進程必須是session leader。第一次fork,setsid之后,子進程成為session leader,進程可以打開終端;第二次fork產生的進程,不再是session leader,進程則無法打開終端。

也就是說,只要程序實現得好,控制程序不主動打開終端,無第二次fork亦可。

代碼實現

# coding: utf-8

import os
import sys
import time
import atexit
import signal


class Daemon:
    def __init__(self, pidfile='/tmp/daemon.pid', stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
        self.stdin = stdin
        self.stdout = stdout
        self.stderr = stderr
        self.pidfile = pidfile

    def daemonize(self):
        if os.path.exists(self.pidfile):
            raise RuntimeError('Already running.')

        # First fork (detaches from parent)
        try:
            if os.fork() > 0:
                raise SystemExit(0)
        except OSError as e:
            raise RuntimeError('fork #1 faild: {0} ({1})\n'.format(e.errno, e.strerror))

        os.chdir('/')
        os.setsid()
        os.umask(0o22)

        # Second fork (relinquish session leadership)
        try:
            if os.fork() > 0:
                raise SystemExit(0)
        except OSError as e:
            raise RuntimeError('fork #2 faild: {0} ({1})\n'.format(e.errno, e.strerror))

        # Flush I/O buffers
        sys.stdout.flush()
        sys.stderr.flush()

        # Replace file descriptors for stdin, stdout, and stderr
        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())

        # Write the PID file
        with open(self.pidfile, 'w') as f:
            print(os.getpid(), file=f)

        # Arrange to have the PID file removed on exit/signal
        atexit.register(lambda: os.remove(self.pidfile))

        signal.signal(signal.SIGTERM, self.__sigterm_handler)

    # Signal handler for termination (required)
    @staticmethod
    def __sigterm_handler(signo, frame):
        raise SystemExit(1)

    def start(self):
        try:
            self.daemonize()
        except RuntimeError as e:
            print(e, file=sys.stderr)
            raise SystemExit(1)

        self.run()

    def stop(self):
        try:
            if os.path.exists(self.pidfile):
                with open(self.pidfile) as f:
                    os.kill(int(f.read()), signal.SIGTERM)
            else:
                print('Not running.', file=sys.stderr)
                raise SystemExit(1)
        except OSError as e:
            if 'No such process' in str(e) and os.path.exists(self.pidfile):
                os.remove(self.pidfile)

    def restart(self):
        self.stop()
        self.start()

    def run(self):
        pass

使用測試

import os
import sys
import time

from daemon import Daemon

class MyTestDaemon(Daemon):
    def run(self):
        sys.stdout.write('Daemon started with pid {}\n'.format(os.getpid()))
        while True:
            sys.stdout.write('Daemon Alive! {}\n'.format(time.ctime()))
            sys.stdout.flush()

            time.sleep(5)

if __name__ == '__main__':
    PIDFILE = '/tmp/daemon-example.pid'
    LOG = '/tmp/daemon-example.log'
    daemon = MyTestDaemon(pidfile=PIDFILE, stdout=LOG, stderr=LOG)

    if len(sys.argv) != 2:
        print('Usage: {} [start|stop]'.format(sys.argv[0]), file=sys.stderr)
        raise SystemExit(1)

    if 'start' == sys.argv[1]:
        daemon.start()
    elif 'stop' == sys.argv[1]:
        daemon.stop()
    elif 'restart' == sys.argv[1]:
        daemon.restart()
    else:
        print('Unknown command {!r}'.format(sys.argv[1]), file=sys.stderr)
        raise SystemExit(1)
[daemon] python test.py start                                         23:45:42
[daemon] cat /tmp/daemon-example.pid                                  23:45:49
8532
[daemon] ps -ef|grep 8532 | grep -v grep                              23:46:07
  502  8532     1   0 11:45下午 ??         0:00.00 python test.py start
[daemon] tail -f /tmp/daemon-example.log                              23:46:20
Daemon started with pid 8532
Daemon Alive! Fri Dec  2 23:45:49 2016
Daemon Alive! Fri Dec  2 23:45:54 2016
Daemon Alive! Fri Dec  2 23:45:59 2016
Daemon Alive! Fri Dec  2 23:46:04 2016
Daemon Alive! Fri Dec  2 23:46:09 2016
Daemon Alive! Fri Dec  2 23:46:14 2016
Daemon Alive! Fri Dec  2 23:46:19 2016
Daemon Alive! Fri Dec  2 23:46:24 2016
Daemon Alive! Fri Dec  2 23:46:29 2016
Daemon Alive! Fri Dec  2 23:46:34 2016

[daemon] python test.py stop                                          23:46:36
[daemon] ps -ef|grep 8532 | grep -v grep                              23:46:43

參考



 
01-05 06:10
护士巨好爽好大乳 - 成男女人看片免费视频播放人 - 久青青在线观看视频国产 - 97中文字幕在线