zoukankan      html  css  js  c++  java
  • python daemon化你的程序

    在之前的树莓派网关项目中遇到了这样一个问题,由于要把网关写的Server持续运行,尤其是要加电自动开启。发现ssh登录开启服务程序之后,当把pty退出时Server端自动断开了,这里想到的APUE中第九章的内容,回顾了下关于会话首进程,进程组,控制终端的概念,所以我们需要把自己写的Server端变为父进程为init(1)的守护进程。

    --->首先想到的办法是使用nohup命令,这里遇到一个坑:

    当我们用nohup去处理shell脚本时是没有问题的,但是在尝试执行一个Python脚本时:

    nohup python tcp_server.py > ser_log.out 2>&1 &

    结果很出了问题:竟然查不到重定向的ser_log.out的输出!后来发现:python的输出有缓冲,导致ser_log.out并不能够马上看到输出。

    我们应该加 -u参数,使得python不启用缓冲,如下:
    nohup python -u tcp_server.py > ser_log.out 2>&1 &

    --->其次,结合最近看的Unix网络编程13章、与APUE13章内容,决定自己尝试写一个daemon,把自己的程序daemon化,代码如下:(守护进程的编程规则可以回顾这篇去年写的:http://www.cnblogs.com/webber1992/p/5850747.html

    #!/usr/bin/env python
    # coding:utf-8
    import os,sys,time
    
    def daemon_init(stdin='/dev/null',stdout='/dev/null',stderr='/dev/null'):
        sys.stdin = open(stdin,'r')
        sys.stdout = open(stdout,'a+')
        sys.stderr = open(stderr,'a+')
        try:
            pid = os.fork()
            if pid > 0:        #parrent
                os._exit(0)
        except OSError,e:
            sys.stderr.write("first fork failed!!"+e.strerror)
            os._exit(1)
    
        # 子进程, 由于父进程已经退出,所以子进程变为孤儿进程,由init收养
    '''setsid使子进程成为新的会话首进程,和进程组的组长,与原来的进程组、控制终端和登录会话脱离。'''
        os.setsid()
    '''防止在类似于临时挂载的文件系统下运行,例如/mnt文件夹下,这样守护进程一旦运行,临时挂载的文件系统就无法卸载了,这里我们推荐把当前工作目录切换到根目录下'''
        os.chdir("/")
    '''设置用户创建文件的默认权限,设置的是权限“补码”,这里将文件权限掩码设为0,使得用户创建的文件具有最大的权限。否则,默认权限是从父进程继承得来的'''
        os.umask(0)
    
        try:
            pid = os.fork()     #第二次进行fork,为了防止会话首进程意外获得控制终端
            if pid > 0:
                os._exit(0)     #父进程退出
        except OSError,e:
            sys.stderr.write("second fork failed!!"+e.strerror)
            os._exit(1)
    
        # 孙进程
    #   for i in range(3,64):  # 关闭所有可能打开的不需要的文件,UNP中这样处理,但是发现在python中实现不需要。
    #       os.close(i)
        sys.stdout.write("Daemon has been created! with pid: %d
    " % os.getpid())
        sys.stdout.flush()  #由于这里我们使用的是标准IO,回顾APUE第五章,这里应该是行缓冲或全缓冲,因此要调用flush,从内存中刷入日志文件。
    
    def main():
        print '========main function start!============' #在调用daemon_init函数前是可以使用print到标准输出的,调用之后就要用把提示信息通过stdout发送到日志系统中了
        daemon_init('/dev/null','/tmp/daemon.log','/tmp/daemon.err')    # 调用之后,你的程序已经成为了一个守护进程,可以执行自己的程序入口了
        time.sleep(10) #daemon化自己的程序之后,sleep 10秒,模拟阻塞
    
    
    if __name__ == '__main__':
        main()

    这样,通过调用daemon_init方法,就可以把自己的程序变为守护进程了,实现了nohup的功能。这样做就更加灵活了,之后的事情就要具体问题具体分析了,比如针对自己实际的应用程序来决定是否要设置umask,是否要关闭不必要的文件描述符,是否要改变当前工作目录等等。

  • 相关阅读:
    MVC的各个部分都有那些技术来实现?如何实现?
    JRE、JDK、JVM 及 JIT 之间有什么不同
    什么是竞态条件?举例说明
    【Spring】No converter found for return value of type: class java.util.ArrayList
    【Spring】org.springframework.web.context.ContextLoaderListen 报错
    【Spring】The matching wildcard is strict……
    【MySQL】目录、文件权限问题
    线程和锁
    【Git】Found a swap file by the name ".git/.MERGE_MSG.swp"
    【Maven】Mac 使用 zsh 后 mvn 命令就无效
  • 原文地址:https://www.cnblogs.com/webber1992/p/6265098.html
Copyright © 2011-2022 走看看