python 守护进程

os模块中的fork方法可以创建一个子进程。相当于克隆了父进程

os.fork()

 

子进程运行时,os.fork方法会返回0;

 而父进程运行时,os.fork方法会返回子进程的PID号。

所以可以使用PID来区分两个进程:

 1 #!/usr/bin/env python
 2 #coding=utf8
 3  
 4 from time import sleep
 5 import os
 6  
 7 try:
 8  pid = os.fork()
 9 except OSError, e:
10  pass
11  
12 sleep(30)
View Code

运行代码,查看进程:

 

[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})\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

  编写自己的类:

 1 #导入刚刚编写的基类
 2 from daemon import Daemon
 3 #继承
 4 class MyTestDaemon(Daemon):
 5 #重写run方法,就是你要后台运行的函数
 6     def run(self):
 7     #后台运行的函数,比如shell输出到自己定义的文件
 8         sys.stdout.write('Daemon started with pid {}\n'.format(os.getpid()))
 9         while True:
10             sys.stdout.write('Daemon Alive! {}\n'.format(time.ctime()))
11             sys.stdout.flush()
12 
13             time.sleep(5)
14 
15 if __name__ == '__main__':
16     PIDFILE = '/tmp/daemon-example.pid'
17     LOG = '/tmp/daemon-example.log'
18     daemon = MyTestDaemon(pidfile=PIDFILE, stdout=LOG, stderr=LOG)
19 
20     if len(sys.argv) != 2:
21         print('Usage: {} [start|stop]'.format(sys.argv[0]), file=sys.stderr)
22         raise SystemExit(1)
23 
24     if 'start' == sys.argv[1]:
25         daemon.start()
26     elif 'stop' == sys.argv[1]:
27         daemon.stop()
28     elif 'restart' == sys.argv[1]:
29         daemon.restart()
30     else:
31         print('Unknown command {!r}'.format(sys.argv[1]), file=sys.stderr)
32         raise SystemExit(1)
33 
34     
my_deamon

 

转载于:https://www.cnblogs.com/zimsan/p/7840306.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值