python 스 크 립 트 를 Liux 데 몬 으로 실행 합 니 다.

7044 단어
링크 ux 데 몬 및 그 특성
데 몬 의 가장 중요 한 기능 은 배경 에서 실행 하 는 것 입 니 다.이 점 에서 도스 의 상주 메모리 프로그램 인 TSR 은 이와 유사 하 다.그 다음으로 데 몬 은 실행 전의 환경 과 격 리 되 어야 합 니 다.이 환경 들 은 닫 히 지 않 은 파일 묘사 서술 자 를 포함 하고 있다.제어 단말기.세 션 과 프로 세 스 그룹, 작업 폴 더, 파일 마스크 생 성 등.
linux 데 몬 과 일반 프로 세 스 의 차이
  • 기본 적 인 상황 에서 프로 세 스 는 프론트 데스크 에서 실 행 됩 니 다. 이 때 셸 을 차지 합 니 다 (로그 출력 이 많 습 니 다). 다른 작업 을 할 수 없습니다.그래서 상호작용 이 없 는 프로 세 스에 대해 배경 에서 시작 하고 싶 을 때 가 많 습 니 다. 매개 변 수 를 시작 할 때 이 목적 을 실현 할 수 있 습 니 다.
  • 데 몬 은 터미널 제어 에서 완전히 벗 어 났 고 배경 프로 세 스 는 터미널 에서 완전히 벗 어 나 지 않 았 으 며 터미널 이 닫 히 기 전에 터미널 로 결 과 를 출력 합 니 다.
  • 데 몬 은 터미널 콘 솔 을 닫 을 때 영향 을 받 지 않 습 니 다. 배경 프로그램 은 사용자 가 종료 할 때 멈 춥 니 다. nohup command & 형식 으로 실행 해 야 영향 을 피 할 수 있 습 니 다.
  • 데 몬 의 세 션 그룹 과 현재 디 렉 터 리, 파일 설명 자 는 모두 독립 되 어 있 습 니 다. 배경 에서 실행 되 는 것 은 터미널 에서 만 fork 를 진행 하여 프로그램 이 배경 에서 실 행 될 수 있 도록 합 니 다. 이것 은 변 함 이 없습니다.

  • Python 데 몬 프로그램 작성 방향
  • fork 하위 프로 세 스, 부모 프로 세 스 가 종 료 됩 니 다. 서버 프로그램 을 실행 할 때 터미널 을 통 해 서버 에 연결 합 니 다. 성공 적 으로 연결 하면 셸 환경 을 불 러 옵 니 다. 터미널 과 셸 은 모두 프로 세 스 입 니 다. 셸 프로 세 스 는 터미널 프로 세 스 의 하위 프로 세 스 입 니 다. ps 명령 을 통 해 쉽게 볼 수 있 습 니 다.이 셸 환경 에서 처음에 실 행 된 프로그램 은 모두 셸 프로 세 스 의 하위 프로 세 스 로 셸 프로 세 스 의 영향 을 받 을 수 있 습 니 다.프로그램 에서 fork 하위 프로 세 스 를 실행 한 후 부모 프로 세 스 가 종료 되 었 습 니 다. 셸 프로 세 스 에 있어 서 이 부모 프로 세 스 는 실행 이 끝 났 더 라 도 하위 프로 세 스 는 init 프로 세 스 에 의 해 연결 되 어 터미널 의 제어 에서 벗 어 났 습 니 다.
  • 하위 프로 세 스 를 수정 하 는 작업 디 렉 터 리 하위 프로 세 스 는 만 들 때 부모 프로 세 스 의 작업 디 렉 터 리 를 계승 합 니 다. 예 를 들 어 Nginx 는 기본 작업 디 렉 터 리/etc/nginx/conf. d/default. conf
  • 가 있 습 니 다.
  • 프로 세 스 그룹 을 만 들 고 setsid 를 사용 하면 하위 프로 세 스 가 새 세 션 의 첫 번 째 프로 세 스 (session leader) 가 됩 니 다.하위 프로 세 스 는 새 프로 세 스 그룹의 팀장 프로 세 스 가 됩 니 다.하위 프로 세 스 가 터미널 을 제어 하지 않 았 습 니 다.
  • umask 를 수정 하면 umask 가 권한 을 차단 하기 때문에 0 으로 설정 하면 파일 을 읽 고 쓸 때 권한 문제 에 부 딪 히 는 것 을 피 할 수 있 습 니 다.
  • fork 손자 프로 세 스, 하위 프로 세 스 가 종료 되면 하위 프로 세 스 는 새로운 프로 세 스 그룹 보스 가 됩 니 다. 터미널 을 다시 신청 할 수 있 습 니 다. 이 문 제 를 피하 기 위해 fork 손자 프로 세 스 가 나 옵 니 다.
  • 손자 프로 세 스 의 표준 입력 흐름, 표준 출력 흐름, 표준 오류 가/dev/null 로 흐 르 는 것 은 데 몬 이기 때문에 그 자체 가 터미널 에서 벗 어 났 기 때문에 표준 입력 흐름, 표준 출력 흐름, 표준 오류 흐름 은 의미 가 없습니다.그래서 모두/dev/null 로 방향 을 바 꾸 는 것 은 모두 버 린 다 는 뜻 입 니 다.

  • 코드 구현
    여기 서 나 는 이런 방식 으로 실현 되 어 나중에 직접 사용 하기에 편리 하 다.
    우선 로그 기록 기 를 만 듭 니 다.
    def creat_handler():
        logger = logging.getLogger(__name__)
        logger.setLevel(logging.INFO)
        # logs/log--            &   
        #        ,         、           、           
        file_log_handler = RotatingFileHandler(LOG_FILE_PATH, maxBytes=1024 * 1024 * 100, backupCount=10)
        #                                  
        formatter = logging.Formatter('%(levelname)s %(filename)s:%(lineno)d - %(asctime)s - %(name)s - %(message)s')
        #                   
        file_log_handler.setFormatter(formatter)
        logger.addHandler(file_log_handler)
        return logger
    

    데 몬 생 성 클래스 정의
    class Daemon(object):
        """python  linux     """
        def __init__(self, pidfile, base_path, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
            #         ,  stdin='/dev/stdin', stdout='/dev/stdout', stderr='/dev/stderr', root    。
            self.stdin = stdin
            self.stdout = stdout
            self.stderr = stderr
            self.pidfile = pidfile
            self.base_path = base_path
    
        def _daemonize(self):
            try:
                pid = os.fork()  #    fork,     ,     
                if pid > 0:
                    sys.exit(0)  #      
            except OSError as e:
                logger.error('fork #1 failed: %d (%s)
    ' % (e.errno, e.strerror)) sys.exit(1) os.chdir("/") # os.setsid() # os.umask(0) # try: pid = os.fork() # fork, if pid > 0: sys.exit(0) except OSError as e: logger.error('fork #2 failed: %d (%s)
    ' % (e.errno, e.strerror)) sys.exit(1) # sys.stdout.flush() sys.stderr.flush() si = open(self.stdin, 'r') so = open(self.stdout, 'a+') se = open(self.stderr, 'a+') os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) # , pid atexit.register(self.delpid) pid = str(os.getpid()) open(self.pidfile, 'w+').write('%s
    ' % pid) def delpid(self): os.remove(self.pidfile) def start(self): # pid try: pf = open(self.pidfile, 'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if pid: message = 'pidfile %s already exist. Daemon already running!
    ' logger.warning(message % self.pidfile) sys.exit(message % self.pidfile) # self._daemonize() self._run() def stop(self): # pid pid try: pf = open(self.pidfile, 'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if not pid: # message = 'pidfile %s does not exist. Daemon not running!
    ' logger.error(message % self.pidfile) return # 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: sys.exit(str(err)) def restart(self): self.stop() self.start() def _run(self): """ """ pass

    사용 예시
    Daemon 계승, run 방법 다시 쓰기
    class MyDaemon(Daemon):
        def _run(self):
            while True:
                os.system("echo 'hello world' >> a.txt")
                time.sleep(1)
                
    

    쓰기 시작 방식
    if __name__ == "__main__":
    	daemon = MyDaemon('/tmp/process.pid', BASE_PATH, stdout='/tmp/stdout.log')
        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()
            else:
                print('unknown command')
                sys.exit(2)
            sys.exit(0)
        else:
            print('usage: %s start|stop|restart' % sys.argv[0])
            sys.exit(2)
    

    시작, 정지, 재 부팅
    python xxx.py start
    
    python xxx.py stop
    
    python xxx.py restart
    

    좋은 웹페이지 즐겨찾기