守護(hù)進(jìn)程(daemon)是指在UNIX或其他多任務(wù)操作系統(tǒng)中在后臺(tái)執(zhí)行的電腦程序,并不會(huì)接受電腦用戶的直接操控。此類程序會(huì)被以進(jìn)程的形式初始化。通常,守護(hù)進(jìn)程沒有任何存在的父進(jìn)程(即PPID=1),且在UNIX系統(tǒng)進(jìn)程層級(jí)中直接位于init之下。守護(hù)進(jìn)程程序通常通過如下方法使自己成為守護(hù)進(jìn)程:對一個(gè)子進(jìn)程調(diào)用fork,然后使其父進(jìn)程立即終止,使得這個(gè)子進(jìn)程能在init下運(yùn)行。–維基百科
守護(hù)進(jìn)程區(qū)別于普通用戶登陸系統(tǒng)后運(yùn)行的進(jìn)程,它是直接由系統(tǒng)初始化,和系統(tǒng)用戶沒有關(guān)系,而用戶開啟的進(jìn)程依存與用戶連接的終端,當(dāng)終端退出或斷開,進(jìn)程也會(huì)隨著終止。
來看一下我Linux試驗(yàn)機(jī)的進(jìn)程狀態(tài):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
[root@home tmp] # ping www.baidu.com > /dev/null & [1] 2759 [root@home tmp] # pstree -p systemd(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) |
可以看到,當(dāng)前有一個(gè)ping程序在后臺(tái)運(yùn)行,如果如斷開連接,再次去登陸,ping程序是已經(jīng)終止了的。也就是說,普通進(jìn)程,和用戶會(huì)話相關(guān),那么,如何去編寫一個(gè)和用戶會(huì)話無關(guān),一直運(yùn)行在后臺(tái)的進(jìn)程呢?大家可能注意到了上面pid為2727的python,如果只是正常打開python,它應(yīng)該是運(yùn)行在bash下的,而這里卻直接運(yùn)行在systemd下,實(shí)際上,它是一個(gè)守護(hù)進(jìn)程,來看一下python編寫linux守護(hù)進(jìn)程的簡單實(shí)現(xiàn):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#!/usr/bin/env python import os import signal import time logfile = "/tmp/daemon.log" pid = os.fork() #exit parent process if pid: exit() #get the pid of subprocess daeid = os.getpid() os.setsid() os.umask( 0 ) os.chdir( "/" ) #Redirection file descriptor fd = 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 ) |
要點(diǎn)是利用linux中,當(dāng)一個(gè)進(jìn)程的父進(jìn)程終止是,系統(tǒng)會(huì)接管這個(gè)進(jìn)程,讓init成為這個(gè)進(jìn)程的父進(jìn)程,這時(shí)候這個(gè)進(jìn)程就成為了一個(gè)守護(hù)進(jìn)程。需要注意的是,通過setsid,umask和chdir做工作目錄設(shè)置、關(guān)閉文件描述符、設(shè)置文件創(chuàng)建掩碼等操作。把上面的代碼保存起來,給于運(yùn)行權(quán)限,并用python打開,就會(huì)看到有一個(gè)新的守護(hù)進(jìn)程在運(yùn)行,并且能夠處理系統(tǒng)發(fā)送的SIGHUP信號(hào)。
以上程序僅用來測試,僅能夠處理系統(tǒng)SIGHUP信號(hào),請使用kill pid結(jié)束進(jìn)程。