守護進程(daemon)是指在UNIX或其他多任務作業系統中在後台執行的電腦程式,並不會接受電腦使用者的直接操控。此類程式會被以進程的形式初始化。通常,守護進程沒有任何存在的父進程(即PPID=1),且在UNIX系統進程層級中直接位於init之下。守護進程程式通常通過如下方法使自己成為守護進程:對一個子進程調用fork,然後使其父進程立即終止,使得這個子進程能在init下運行。–維基百科
守護進程區別於普通使用者登陸系統後啟動並執行進程,它是直接由系統初始化,和系統使用者沒有關係,而使用者開啟的進程依存與使用者串連的終端,當終端退出或斷開,進程也會隨著終止。
來看一下我Linux實驗機的進程狀態:
[root@home tmp]# ping www.baidu.com > /dev/null &[1] 2759[root@home tmp]# pstree -psystemd(1)-+-agetty(157) |-agetty(163) |-avahi-daemon(129)---avahi-daemon(134) |-avahi-dnsconfd(125) |-crond(121) |-dbus-daemon(130) |-haveged(128) |-ifplugd(126) |-nginx(226)---nginx(227) |-ntpd(223) |-python(2727) |-rngd(124) |-sshd(216)---sshd(2683)---bash(2690)-+-ping(2759) | `-pstree(2760) |-systemd(2687)---(sd-pam)(2688) |-systemd-journal(76) |-systemd-logind(127) |-systemd-udevd(89) `-wpa_supplicant(153)
可以看到,當前有一個ping程式在後台運行,如果如中斷連線,再次去登陸,ping程式是已經終止了的。也就是說,普通進程,和使用者會話相關,那麼,如何去編寫一個和使用者會話無關,一直運行在背景進程呢?大家可能注意到了上面pid為2727的python,如果只是正常開啟python,它應該是運行在bash下的,而這裡卻直接運行在systemd下,實際上,它是一個守護進程,來看一下python編寫linux守護進程的簡單實現:
#!/usr/bin/env pythonimport osimport signalimport timelogfile="/tmp/daemon.log"pid=os.fork()#exit parent processif pid: exit()#get the pid of subprocessdaeid=os.getpid()os.setsid()os.umask(0)os.chdir("/")#Redirection file descriptorfd=open("/dev/null","a+")os.dup2(fd.fileno(),0)os.dup2(fd.fileno(),1)os.dup2(fd.fileno(),2)fd.close()log=open(logfile,'a')log.write('Daemon start up at %s\n'%(time.strftime('%Y:%m:%d',time.localtime(time.time()))))log.close()def reload(a,b): log=open(logfile,'a') log.write('Daemon reload at %s\n'%(time.strftime('%Y:%m:%d',time.localtime(time.time())))) log.close()while True: signal.signal(signal.SIGHUP,reload) time.sleep(2)
要點是利用linux中,當一個進程的父進程終止是,系統會接管這個進程,讓init成為這個進程的父進程,這時候這個進程就成為了一個守護進程。需要注意的是,通過setsid,umask和chdir做工作目錄設定、關閉檔案描述符、設定檔案建立掩碼等操作。把上面的代碼儲存起來,給於運行許可權,並用python開啟,就會看到有一個新的守護進程在運行,並且能夠處理系統發送的SIGHUP訊號。
以上程式僅用來測試,僅能夠處理系統SIGHUP訊號,請使用kill pid結束進程。