python 은 fork 를 사용 하여 데 몬 을 실현 하 는 방법

14013 단어 python데 몬
os 모듈 의 fork 방법 은 하위 프로 세 스 를 만 들 수 있 습 니 다.부모 프로 세 스 를 복제 한 셈 이다.
os.fork()
하위 프로 세 스 가 실 행 될 때 os.fork 방법 은 0 으로 돌아 갑 니 다.
 부모 프로 세 스 가 실 행 될 때 os.fork 방법 은 하위 프로 세 스 의 PID 번 호 를 되 돌려 줍 니 다.
따라서 PID 를 사용 하여 두 프로 세 스 를 구분 할 수 있 습 니 다.

 #!/usr/bin/env python
 #coding=utf8
 
 from time import sleep
 import os
 
 try:
 pid = os.fork()
 except OSError, e:
 pass
 
 sleep(30)

실행 코드,프로 세 스 보기:

[root@localhost ~]# python test2.py &

[1] 2464

[root@localhost ~]# ps -l

F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD

4 S 0 2379 2377 0 80 0 - 28879 wait pts/1 00:00:00 bash

0 S 0 2464 2379 0 80 0 - 31318 poll_s pts/1 00:00:00 python

1 S 0 2465 2464 0 80 0 - 31318 poll_s pts/1 00:00:00 python

0 R 0 2466 2379 0 80 0 - 37227 - pts/1 00:00:00 ps​

두 번 째 python 프로 세 스 가 첫 번 째 하위 프로 세 스 임 을 알 수 있 습 니 다.
방금 말 한 바 와 같이 os.fork()방법 구역 분자 프로 세 스 와 부모 프로 세 스

#-*- coding:utf-8 -*-
 
from time import sleep
import os
 
print('start+++++++++++++')
#            
source = 10
try:
    pid = os.fork()
    print('pid=',pid)
    if pid == 0: #   
        print("this is child process.")
        source = source - 1 #     source 1
    else: #   
        print("this is parent process." )
    print(source)
except (OSError,e):
    pass
print('END---------------')
  

면 코드 에 서 는 하위 프로 세 스 가 생 성 되 기 전에 변수 source 를 설명 한 다음 하위 프로 세 스 에서 1 을 줄 이 고 마지막 으로 source 의 값 을 출력 합 니 다.부모 프로 세 스 가 인쇄 한 값 은 10 이 어야 하고 하위 프로 세 스 가 인쇄 한 값 은 9 여야 합 니 다.

[root@localhost ~]# python test3.py
start+++++++++++++
pid= 2550
this is parent process.
10
END---------------
pid= 0
this is child process.
9
END---------------​
  

 간단 한 데 몬 예:

def main():
  '''            '''
  pass
 
 
#         
def createDaemon():
  '''    (        ) '''
  # fork       (  fork  ,     ,               )
  try:
    if os.fork() > 0:
      sys.exit(0)
  except OSError, error:
    print '(fork        )fork #1 failed: %d (%s)' % (error.errno, error.strerror)
    sys.exit(1)
  '''       '''
 
  ######           ,  ppid = 1,         ,            。
  ######              。                ,     ,     。
  ######            。 
 
 
  os.chdir('/') #                 / (   )
  os.setsid() #              
  os.umask(0) #                  (   rwx)
 
 
  '''    (        ) '''
  # fork       (  fork  ,        ,             )
  try:
    pid = os.fork()
    if pid > 0:
      print 'Daemon PID %d' % pid
      sys.exit(0)
  except OSError, error:
    print '(fork        )fork #2 failed: %d (%s)' % (error.errno, error.strerror)
    sys.exit(1)
  '''       '''
 
 
  #######        try    ,              。         ppid=1。
  #######          ,               。
 
 
 
  #      IO(              ,              、  、   )
   
  # sys.stdout.flush() #             
  # sys.stderr.flush() #             
 
  # inputS = file("/dev/null", 'r')  #      inputS     
  # outputS = file("/dev/null", 'a+') #      outputS     
  # errorS = file("/dev/null", 'a+', 0) #      errorS     
 
  # os.dup2(inputS.fileno(), sys.stdin.fileno()) #                  inputS      。
  # os.dup2(so.fileno(), sys.stdout.fileno()) #                    outputS      。
  # os.dup2(se.fileno(), sys.stderr.fileno()) #                    errorS      。
 
  main() # main           
 
 
if __name__ == "__main__":
  if platform.system() == "Linux":
      createDaemon()
    else:
      sys.exit()
  
  

 제어 인자 가 있 는 예:
데 몬 의 기본 클래스 를 작성 하여 계승 에 사용 합 니 다:

# 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})
'.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})
'.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
클래스 만 들 기:

 #         
 from daemon import Daemon
 #  
 class MyTestDaemon(Daemon):
 #  run  ,           
   def run(self):
   #       ,  shell          
     sys.stdout.write('Daemon started with pid {}
'.format(os.getpid())) while True: sys.stdout.write('Daemon Alive! {}
'.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)
포크
두 번 째 포크 는 필수 가 아 닙 니 다.프로 세 스 가 제어 단말 기 를 여 는 것 을 방지 하기 위해 서 입 니 다.
제어 단말 기 를 여 는 조건 은 이 프로 세 스 가 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})
'.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})
'.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 {}
'.format(os.getpid())) while True: sys.stdout.write('Daemon Alive! {}
'.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

좋은 웹페이지 즐겨찾기