守護程序:通常被定義為乙個後台程序,而且它不屬於任何乙個終端會話(terminal session)。許多系統服務由守護程式實施;如網路服務,列印等。
1. 呼叫fork()以便父程序可以退出,這樣就將控制權歸還給執行你程式的命令列或shell程式。需要這一步以便保證新程序不是乙個程序組頭領程序(process group leader)。下一步,『setsid()』,會因為你是程序組頭領程序而失敗。
說明:當程序是會話的領頭程序時setsid()呼叫失敗並返回(-1)。setsid()呼叫成功後,返回新的會話的id,呼叫setsid函式的程序成為新的會話的領頭程序,並與其父程序的會話組和程序組脫離。由於會話對控制終端的獨占性,程序同時與控制終端脫離。 (setsid() unix命令)
2. 呼叫『setsid()』 以便成為乙個程序組和會話組的頭領程序。由於乙個控制終端與乙個會話相關聯,而且這個新會話還沒有獲得乙個控制終端,我們的程序沒有控制終端,這對於守護程式來說是一件好事。
3. 再次呼叫『fork()』所以父程序(會話組頭領程序)可以退出。這意味著我們,乙個非會話組頭領程序永遠不能重新獲得控制終端。
4. 呼叫『chdir("/")』確認我們的程序不保持任何目錄於使用狀態。不做這個會導致系統管理員不能卸裝(umount)乙個檔案系統,因為它是我們的當前工作目錄。 [類似的,我們可以改變當前目錄至對於守護程式執行重要的檔案所在目錄]
5. 呼叫『umask(0)』以便我們擁有對於我們寫的任何東西的完全控制。我們不知道我們繼承了什麼樣的umask。 [這一步是可選的](譯者注:這裡指步驟5,因為守護程式不一定需要寫檔案)
6. 呼叫『close()』關閉檔案描述符0,1和2。這樣我們釋放了從父程序繼承的標準輸入,標準輸出,和標準錯誤輸出。我們沒辦法知道這些文描述符符可能 已經被重定向去**。注意到許多守護程式使用『sysconf()』來確認『_sc_open_max』的限制。『_sc_open_max』告訴你每個 程序能夠開啟的最多檔案數。然後使用乙個迴圈,守護程式可以關閉所有可能的檔案描述符。你必須決定你需要做這個或不做。如果你認為有可能有開啟的檔案描述 符,你需要關閉它們,因為系統有乙個同時開啟檔案數的限制。
說實話,上面這段文字看著有點雲裡霧裡,下面看個具體的**(我只貼上了函式的第一部分,也是最重要的一部分,要檢視整個**,請移步到這 highlight=自行檢視):
#encoding:utf-8
import os,sys,time
stdout = "/dev/null"
stdin = "/dev/null"
stderr = none
pidfile = "./.daemon.pid"
if pidfile:
print("pid file alread exist!")
sys.stdout.flush()
sys.stdin.flush()
try:
pid = os.fork()
if pid > 0:
sys.exit() #父程序退出只剩下子程序
except oserror,e:
sys.stderr.write("fork #1 failed:(%d)%s\n" % (e.errno,e.strerror))
sys.exit()
#呼叫『chdir("/")』確認我們的程序不保持任何目錄於使用狀態。不做這個會導致系統管理員不能卸裝(umount)乙個檔案系統,因為它是我們的當前工作目錄。 [類似的,我們可以改變當前目錄至對於守護程式執行重要的檔案所在目錄]
#改變當前程序執行目錄
os.chdir("/")
#使當前執行緒 擁有檔案讀寫許可權
os.umask(0)
#使子執行緒 脫離父執行緒的程序組,會話組,是子程序成為新的的頭領, 程序同時與會話脫離 ,
os.setsid()
try:
pid = os.fork() #父程序的會話頭領可以退出,以為著非會話頭領程序永遠不可能獲得終端
if pid > 0 :
sys.exit()
except oserror,e:
sys.stderr.write("fork #2 failed:(%d)%s\n" % (e.errno,e.strerror))
#呼叫close關閉從父程序繼承過來的標準輸入輸出
if not stderr:
stderr = stdout
si = file(stdin,'r')
so = file(stdout,'a+')
se = file(stderr,'a+',0)#ubuffered
pid = str(os.getpid())
print("daemon process id:%s" % pid)
sys.stderr.write("\n%s\n" % pid)
sys.stderr.flush()
if pidfile:
abspath = os.path.abspath(pidfile)
print(abspath)
print("write to pid file :true")
open(pidfile,"a").write("%s\n" % pid)
#改變檔案符號
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(),sys.stdout.fileno())
os.dup2(se.fileno(),sys.stderr.fileno())
父程序執行**到os.fork()處時,會將自己整個拷貝乙份(即子程序)這時候父程序os.fork()的返回值大於零(即子程序的pid), 子程序os.fork()的返回值等於零,父程序結束,子程序繼續執行,這時候又遇到第二個os.fork(),如上次一樣,原來的子程序變成了父程序, 又產生新的子程序,之後父程序就結束。這就能夠說通第一次是避免process group leader,第二次是避免session group leader。子程序就變成了乙個無終端,無會話的完全自我掌控的後台程序了。
文章出處:
編寫守護程序
include include include include include include void main int argc,char argv 守護程序在linux unix系統中有著廣泛的應用。有時,開發人員也想把自己的程式變成守護程序。在建立乙個守護程序的時候,要接觸到子程序 程序組 ...
編寫Linux Unix守護程序
守護程序在linux unix系統中有著廣泛的應用。有時,開發人員也想把自己的程式變成守護程序。在建立乙個守護程序的時候,要接觸到子程序 程序組 會晤期 訊號機制 檔案 目錄和控制終端等多個概念。因此守護程序還是比較複雜的,在這裡詳細地討論linux unix的守護程序的編寫,總結出八條經驗,並給出...
用Python給Linux編寫守護程序
守護程序 daemon 是指在unix或其他多工作業系統中在後台執行的電腦程式,並不會接受電腦使用者的直接操控。此類程式會被以程序的形式初始化。通常,守護程序沒有任何存在的父程序 即ppid 1 且在unix系統程序層級中直接位於init之下。守護程序程式通常通過如下方法使自己成為守護程序 對乙個子...