python中的daemon守护进程实现方法
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                python中的daemon守护进程实现方法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                
                            
                            
                            守護進程是生存期長的一種進程。它們獨立于控制終端并且周期性的執行某種任務或等待處理某些發生的事件。他們常常在系統引導裝入時啟動,在系統關閉時終止。
 
守護進程的特性
1.在后臺運行
2.與其運行前的環境隔離開來。這些環境包括未關閉的文件描述符、控制終端、會話和進程組、工作目錄以及文件創建掩碼等。這些環境通常是守護進程從執行它的父進程(特別是shell)中繼承下來的。
3.啟動方式特殊,它可以在系統啟動時從啟動腳本/etc/rc.d中啟動,可以由inetd守護進程啟動,可以由crond啟動,還可以由用戶終端(通常是shell)執行。
總之,除開這些特殊性以外,守護進程與普通進程基本上沒有什么區別。因此,編寫守護進程實際上是把一個普通進程按照上述的守護進程的特性改造成為守護進程。
 
守護進程編程規則
1.在后臺運行,調用fork ,然后使父進程exit
2.脫離控制終端,登錄會話和進程組,調用setsid()使進程成為會話組長
3.禁止進程重新打開控制終端
4.關閉打開的文件描述符,調用fclose()
5.將當前工作目錄更改為根目錄。
6.重設文件創建掩碼為0
7.處理SIGCHLD 信號
 
 
 
 
                            
                        
                        
                        守護進程的特性
1.在后臺運行
2.與其運行前的環境隔離開來。這些環境包括未關閉的文件描述符、控制終端、會話和進程組、工作目錄以及文件創建掩碼等。這些環境通常是守護進程從執行它的父進程(特別是shell)中繼承下來的。
3.啟動方式特殊,它可以在系統啟動時從啟動腳本/etc/rc.d中啟動,可以由inetd守護進程啟動,可以由crond啟動,還可以由用戶終端(通常是shell)執行。
總之,除開這些特殊性以外,守護進程與普通進程基本上沒有什么區別。因此,編寫守護進程實際上是把一個普通進程按照上述的守護進程的特性改造成為守護進程。
守護進程編程規則
1.在后臺運行,調用fork ,然后使父進程exit
2.脫離控制終端,登錄會話和進程組,調用setsid()使進程成為會話組長
3.禁止進程重新打開控制終端
4.關閉打開的文件描述符,調用fclose()
5.將當前工作目錄更改為根目錄。
6.重設文件創建掩碼為0
7.處理SIGCHLD 信號
下面是一個的demo源碼示例:
#!/usr/bin/env python
#encoding: utf-8
#description: 一個守護進程的簡單包裝類, 具備常用的start|stop|restart|status功能, 使用方便
#             需要改造為守護進程的程序只需要重寫基類的run函數就可以了
#date: 2015-10-29
#usage: 啟動: python daemon_class.py start
#       關閉: python daemon_class.py stop
#       狀態: python daemon_class.py status
#       重啟: python daemon_class.py restart
#       查看: ps -axj | grep daemon_classimport atexit, os, sys, time, signalclass CDaemon:'''a generic daemon class.usage: subclass the CDaemon class and override the run() methodstderr  表示錯誤日志文件絕對路徑, 收集啟動過程中的錯誤日志verbose 表示將啟動運行過程中的異常錯誤信息打印到終端,便于調試,建議非調試模式下關閉, 默認為1, 表示開啟save_path 表示守護進程pid文件的絕對路徑'''def __init__(self, save_path, stdin=os.devnull, stdout=os.devnull, stderr=os.devnull, home_dir='.', umask=022, verbose=1):self.stdin = stdinself.stdout = stdoutself.stderr = stderrself.pidfile = save_path #pid文件絕對路徑self.home_dir = home_dirself.verbose = verbose #調試開關self.umask = umaskself.daemon_alive = Truedef daemonize(self):try:pid = os.fork()if pid > 0:sys.exit(0)except OSError, e:sys.stderr.write('fork #1 failed: %d (%s)\n' % (e.errno, e.strerror))sys.exit(1)os.chdir(self.home_dir)os.setsid()os.umask(self.umask)try:pid = os.fork()if pid > 0:sys.exit(0)except OSError, e:sys.stderr.write('fork #2 failed: %d (%s)\n' % (e.errno, e.strerror))sys.exit(1)sys.stdout.flush()sys.stderr.flush()si = file(self.stdin, 'r')so = file(self.stdout, 'a+')if self.stderr:se = file(self.stderr, 'a+', 0)else:se = soos.dup2(si.fileno(), sys.stdin.fileno())os.dup2(so.fileno(), sys.stdout.fileno())os.dup2(se.fileno(), sys.stderr.fileno())def sig_handler(signum, frame):self.daemon_alive = Falsesignal.signal(signal.SIGTERM, sig_handler)signal.signal(signal.SIGINT, sig_handler)if self.verbose >= 1:print 'daemon process started ...'atexit.register(self.del_pid)pid = str(os.getpid())file(self.pidfile, 'w+').write('%s\n' % pid)def get_pid(self):try:pf = file(self.pidfile, 'r')pid = int(pf.read().strip())pf.close()except IOError:pid = Noneexcept SystemExit:pid = Nonereturn piddef del_pid(self):if os.path.exists(self.pidfile):os.remove(self.pidfile)def start(self, *args, **kwargs):if self.verbose >= 1:print 'ready to starting ......'#check for a pid file to see if the daemon already runspid = self.get_pid()if pid:msg = 'pid file %s already exists, is it already running?\n'sys.stderr.write(msg % self.pidfile)sys.exit(1)#start the daemonself.daemonize()self.run(*args, **kwargs)def stop(self):if self.verbose >= 1:print 'stopping ...'pid = self.get_pid()if not pid:msg = 'pid file [%s] does not exist. Not running?\n' % self.pidfilesys.stderr.write(msg)if os.path.exists(self.pidfile):os.remove(self.pidfile)return#try to kill the daemon processtry:i = 0while 1:os.kill(pid, signal.SIGTERM)time.sleep(0.1)i = i + 1if i % 10 == 0:os.kill(pid, signal.SIGHUP)except OSError, err:err = str(err)if err.find('No such process') > 0:if os.path.exists(self.pidfile):os.remove(self.pidfile)else:print str(err)sys.exit(1)if self.verbose >= 1:print 'Stopped!'def restart(self, *args, **kwargs):self.stop()self.start(*args, **kwargs)def is_running(self):pid = self.get_pid()#print(pid)return pid and os.path.exists('/proc/%d' % pid)def run(self, *args, **kwargs):'NOTE: override the method in subclass'print 'base class run()'class ClientDaemon(CDaemon):def __init__(self, name, save_path, stdin=os.devnull, stdout=os.devnull, stderr=os.devnull, home_dir='.', umask=022, verbose=1):CDaemon.__init__(self, save_path, stdin, stdout, stderr, home_dir, umask, verbose)self.name = name #派生守護進程類的名稱def run(self, output_fn, **kwargs):fd = open(output_fn, 'w')while True:line = time.ctime() + '\n'fd.write(line)fd.flush()time.sleep(1)fd.close()if __name__ == '__main__':help_msg = 'Usage: python %s <start|stop|restart|status>' % sys.argv[0]if len(sys.argv) != 2:print help_msgsys.exit(1)p_name = 'clientd' #守護進程名稱pid_fn = '/tmp/daemon_class.pid' #守護進程pid文件的絕對路徑log_fn = '/tmp/daemon_class.log' #守護進程日志文件的絕對路徑err_fn = '/tmp/daemon_class.err.log' #守護進程啟動過程中的錯誤日志,內部出錯能從這里看到cD = ClientDaemon(p_name, pid_fn, stderr=err_fn, verbose=1)if sys.argv[1] == 'start':cD.start(log_fn)elif sys.argv[1] == 'stop':cD.stop()elif sys.argv[1] == 'restart':cD.restart(log_fn)elif sys.argv[1] == 'status':alive = cD.is_running()if alive:print 'process [%s] is running ......' % cD.get_pid()else:print 'daemon process [%s] stopped' %cD.nameelse:print 'invalid argument!'print help_msg產生的日志文件為
參考文檔 http://zhidao.baidu.com/link?url=3oGf3-g9x9tlR-VrYaG-hc8HiyXxKQznCXBe1C7M4rxzbbbOokOHkYi-VV9mcZ5dvljekexegBolO-5MCSyUpXp3Uv4--7-5GNDBLSqqD0S?很有參考價值 http://blog.csdn.net/mr_jj_lian/article/details/7252222?原理講解非常到位 http://www.jb51.net/article/54199.htm?都不錯,這個守護進程類包裝非常完備,我已經重新整理了一遍總結
以上是生活随笔為你收集整理的python中的daemon守护进程实现方法的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 通过python的ConfigParse
- 下一篇: Python中*args 和**kwar
