守護進程

守護進程

1、定義:

    守護進程:脫離終端並且在後臺運行的進程

    守護進程脫離終端:避免進程在執行過程中的信息在任何終端上顯示;進程不會被任何終端所產生的終端信息所打斷


2、創建步驟:

    創建子進程,退出父進程:

        使用fork()函數和if判斷語句,使子進程變爲孤兒進程,交給init進程管理

pid = os.fork()         #調用fork()函數
if pid < 0:             #小於0,表明調用fork失敗
    print 'invoke fork() failure'
    sys.exit(1)         #退出腳本
elif pid > 0:           #大於0,表明是父進程
    sys.exit(0)         #退出父進程

    在子進程中創建新會話:

        這個步驟是創建守護進程中最重要的一步;調用fork函數創建子進程時,子進程繼承了父進程的全部資源環境(包括會話期、進程組、控制終端等),雖然父進程退出了,但會話期、進程組、控制終端等並沒有改變,因此,子進程並沒有真正的獨立出來,而setsid函數能夠使子進程完全獨立出來

os.setsid()             #調用setsid()函數

    改變當前目錄爲根目錄:

        調用fork()函數創建子進程,子進程也會繼承父進程的當前工作目錄,若子進程使用父進程的當前工作目錄可能會有一些問題

os.chdir("/")

    重設文件權限掩碼:

        把文件權限掩碼設置爲0,可以大大增強守護進程的靈活性

os.umask(0)


3、一個創建守護進程的實例:

vi /tmp/dir1/file.py
#encoding:utf-8
import os
import sys
import time
import commands

pid = os.fork()         #調用fork()函數
if pid < 0:             #小於0,表面調用fork失敗
    print 'invoke fork() failure'
    sys.exit(1)         #退出腳本
elif pid > 0:           #大於0,表面是父進程
    sys.exit(0)         #退出父進程,下面所有命令都是在子進程下執行

os.setsid()             #在子進程中調用setsid函數
os.chdir("/")
os.umask(0)
while True:
    os.system('echo `date +%F-%H%M%S` >> /tmp/dir1/file')
    time.sleep(1)

 

[root@scj dir1]# python /tmp/dir1/file.py 
[root@scj dir1]# ps -ef | grep file.py
root      3282     1  0 02:46 ?        00:00:00 python /tmp/dir1/file.py
root      3311  1575  0 02:46 pts/1    00:00:00 grep file.py

由上發現:file.py被放在後臺作爲守護進程運行,父進程號是1(也就是init進程)

注意:守護進程由init進程管理

[root@scj dir1]# tail -f /tmp/dir1/file
2015-06-23-025041
2015-06-23-025042
2015-06-23-025043
2015-06-23-025044
2015-06-23-025045
2015-06-23-025046
2015-06-23-025047
2015-06-23-025048
2015-06-23-025049
2015-06-23-025050
2015-06-23-025051
2015-06-23-025052
2015-06-23-025053
2015-06-23-025054

每秒執行一次


4、停止守護進程的方法:

    使用kill殺死

[root@scj dir1]# ps -ef | grep file.py
root      3282     1  0 02:46 ?        00:00:00 python /tmp/dir1/file.py
root      4195  1575  0 02:51 pts/1    00:00:00 grep file.py
[root@scj dir1]# kill -9 3282





python守護進程的完整實例:

# -*-coding:utf-8-*-
import sys, os

'''將當前進程fork爲一個守護進程

    注意:如果你的守護進程是由inetd啓動的,不要這樣做!inetd完成了
    所有需要做的事情,包括重定向標準文件描述符,需要做的事情只有
    chdir() 和 umask()了
'''
def daemonize(stdin='/dev/null',stdout= '/dev/null', stderr= 'dev/null'):
    '''Fork當前進程爲守護進程,重定向標準文件描述符
        (默認情況下定向到/dev/null)
    '''
    #Perform first fork.
    try:
        pid = os.fork()
        if pid > 0:
            sys.exit(0)  #first parent out
    except OSError, e:
        sys.stderr.write("fork #1 failed: (%d) %s\n" %(e.errno, e.strerror))
        sys.exit(1)

    #從母體環境脫離
    os.chdir("/")
    os.umask(0)
    os.setsid()
    #執行第二次fork
    try:
        pid = os.fork()
        if pid > 0:
            sys.exit(0) #second parent out
    except OSError, e:
        sys.stderr.write("fork #2 failed: (%d) %s]n" %(e.errno,e.strerror))
        sys.exit(1)

    #進程已經是守護進程了,重定向標準文件描述符
    for f in sys.stdout, sys.stderr: 
        f.flush()
    si = file(stdin, 'r')
    so = file(stdout,'a+')
    se = file(stderr,'a+',0)
    os.dup2(si.fileno(), sys.stdin.fileno())
    os.dup2(so.fileno(), sys.stdout.fileno())
    os.dup2(se.fileno(), sys.stderr.fileno())

def _example_main():
    '''示例函數:每秒打印一個數字和時間戳'''
    import time
    sys.stdout.write('Daemon started with pid %d\n' % os.getpid())
    sys.stdout.write('Daemon stdout output\n')
    sys.stderr.write('Daemon stderr output\n')

    c = 0
    while True:
        sys.stdout.write('%d: %s\n' %(c, time.ctime()))
        sys.stdout.flush()
        c = c+1
        time.sleep(1)

if __name__ == "__main__":
    daemonize('/dev/null','/home/hzhida/daemon.log','home/hzhida/daemon.log')
    _example_main()

#第一個fork是爲了讓shell返回,同時讓你完成setsid(從你的控制終端移除,這樣就不會意外地收到信號)。setsid使得這個進程成爲“會話領導(session leader)”,即如果這個進程打開任何終端,該終端就會成爲此進程的控制終端。我們不需要一個守護進程有任何控制終端,所以我們又fork一次。在第二次fork之後,此進程不再是一個“會話領導”,這樣它就能打開任何文件(包括終端)且不會意外地再次獲得一個控制終端


另外說明:

umask()函數爲進程設置文件模式創建屏蔽字,並返回以前的值

在shell命令行輸入:umask 就可知當前文件模式創建屏蔽字

常見的幾種umask值是002,022和027,002阻止其他用戶寫你的文件,022阻止同組成員和其他用戶寫你的文件,027阻止同組成員寫你的文件以及其他用戶讀寫或執行你的文件

rwx-rwx-rwx  代表是777  所有的人都具有權限讀寫與執行


chmod()改變文件的權限位

int dup(int filedes) 返回新文件描述符一定是當前文件描述符中的最小數值

int dup2(int filedes, int filedes2);這兩個函數返回的新文件描述符與參數filedes共享同一個文件表項。


sys.stdout.flush():python的輸出(stdout,stderr)是有緩衝區的

    flush()方法會直接把內部緩衝區的數據立刻寫入文件,而不是被動的等待輸出緩衝區被寫入

obj.fileno():獲取打開文件的描述符

os.dup2(f1,f2):複製f1的文件描述符到f2












發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章