python程序守護

2021-08-15 10:18:32 字數 3732 閱讀 1095

參考:

- vamei

- python守護程序daemon實現

如何建立乙個程序

實際上,當計算機開機的時候,核心(kernel)只建立了乙個init程序。linux核心並不提供直接建立新程序的系統呼叫。剩下的所有程序都是init程序通過fork機制建立的。新的程序要通過老的程序複製自身得到,這就是fork。fork是乙個系統呼叫。程序存活於記憶體中。每個程序都在記憶體中分配有屬於自己的一片空間 (address space)。當程序fork的時候,linux在記憶體中開闢出一片新的記憶體空間給新的程序,並將老的程序空間中的內容複製到新的空間中,此後兩個程序同時執行。

老程序成為新程序的父程序(parent process),而相應的,新程序就是老的程序的子程序(child process)。乙個程序除了有乙個pid之外,還會有乙個ppid(parent pid)來儲存的父程序pid。如果我們循著ppid不斷向上追溯的話,總會發現其源頭是init程序。所以說,所有的程序也構成乙個以init為根的樹狀結構。

ork通常作為乙個函式被呼叫。這個函式會有兩次返回,將子程序的pid返回給父程序,0返回給子程序。實際上,子程序總可以查詢自己的ppid來知道自己的父程序是誰,這樣,一對父程序和子程序就可以隨時查詢對方。

通常在呼叫fork函式之後,程式會設計乙個if選擇結構。當pid等於0時,說明該程序為子程序,那麼讓它執行某些指令,比如說使用exec庫函式(library function)讀取另乙個程式檔案,並在當前的程序空間執行 (這實際上是我們使用fork的一大目的: 為某一程式建立程序);而當pid為乙個正整數時,說明為父程序,則執行另外一些指令。由此,就可以在子程序建立之後,讓它執行與父程序不同的功能。

守護程序編寫思路

詳細參見: 《advancedprogrammingin the unix environment》section 13.3 page 583

1、呼叫umask將檔案模式建立遮蔽字設定為乙個已知值(通常是0)。如前所述,由繼承得來的檔案模式建立遮蔽字可能會被設定為拒絕許可權。我們可以根據我們的具體需求設定特定的許可權。

2、呼叫fork,然後使父程序exit。這樣做,使得當我們以./的shell命令啟動守護程序時,父程序終止會讓shell認為此命令已經執行完畢,而且,這也使子程序獲得了乙個新的程序id。此外,讓父程序先於子程序exit,會使子程序變為孤兒程序,這樣子程序成功被init這個使用者級守護程序收養。

3、呼叫setsid建立乙個新會話。這在setsid函式中有介紹,呼叫setsid,會使這個子程序成為(a)新會話的首程序,(b)成為乙個新程序組的組長程序,(c)切斷其與控制終端的聯絡,或者就是沒有控制終端。至此,這個子程序作為新的程序組的組長,完全脫離了其他程序的控制,並且沒有控制終端。

4、將當前工作目錄更改為根目錄(或某一特定目錄位置)。這是為了保證守護程序的當前工作目錄在乙個掛載的檔案系統中,該檔案系統不能被解除安裝。

5、關閉不再需要的檔案描述符。根據具體情況來定。

6、某些守護程序可以開啟/dev/null使其具有檔案描述符0、1、2,這使任何乙個試圖讀標準輸入、寫標準輸出或標準錯誤的庫例程都不會產生任何效果。

7、忽略sigchld訊號

這一步並非必須的,只對需要建立子程序的守護程序才有必要,很多伺服器守護程序設計成通過派生子程序來處理客戶端的請求,如果父程序不對sigchld訊號進行處理的話,子程序在終止後變成殭屍程序,通過將訊號sigchld的處理方式設定為sig_ign可以避免這種情況發生。

8、用日誌系統記錄出錯資訊

因為守護程序沒有控制終端,當程序出現錯誤時無法寫入到標準輸出上,可以通過呼叫syslog將出錯資訊寫入到指定的檔案中。該介面函式包括openlog、syslog、closelog、setlogmask,具體可參考13.4節出錯記錄。

9、守護程序退出處理

當使用者需要外部停止守護程序執行時,往往會使用 kill命令停止該守護程序。所以,守護程序中需要編碼來實現kill發出的signal訊號處理,達到程序的正常退出。

總結守護程序程式設計規則

python**實現

#!/usr/bin/env python  

# coding:utf-8

import os,sys,time

defdaemon_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: # judge if pid is parent id

os._exit(0) # kill parent id

except oserror as 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 as e:

sys.stderr.write("second fork failed"+e.strerror)

sys.stdout.write("daemon has been created! with pid: %d\n" % os.getpid())

sys.stdout.flush() #由於這裡我們使用的是標準io,回顧apue第五章,這裡應該是行緩衝或全緩衝,因此要呼叫flush,從記憶體中刷入日誌檔案。

defmain

():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()

python守護程序

去 python daemon 1.5.2 3.el5.noarch.rpm 測試 test.py usr bin python import daemon,time print 1 p daemon.daemoncontext p.open for i in range 0,100 print t...

Python守護程序

關於python守護程序,網上查了一些資料,做下彙總 1.python例項 之五python守護程序和指令碼單例執行 2.python 模擬linux守護程序 3.python中fork 函式生成子程序分析 4.討論一下os.umask 和os.setsid 5.用python編寫linux守護程序...

python 守護程序

主程式也是乙個程序,只是我們看不到,需要借助函式列印。包括子程序也可以列印。threading.current thread 檢視當前執行緒 import threading import time def run n print task n time.sleep 2 print task don...