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\n" % 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,是否要關閉不必要的文件描述符,是否要改變當前工作目錄等等。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM