Python实现Daemon(守护)进程

发布时间:2019-09-04 06:48:11编辑:auto阅读(1636)

    最近在写Daemon进程,在编写过程中遇到一些小麻烦,最终还是解决了。

    我编写了两种,第一种是编写了一个程序,将其用setsid命令让其放入后台运行,第二种是直接fork()一个进程,在代码里将进程设置为后台启动。

    在os.sytem()函数其他外部程序时,发现os.system()是阻塞的(os.popen()也是阻塞的),就是启动外部程序,你必须等外部程序退出,它才继续运行。用python中的subprocess库时,发现它并不阻塞主进程的运行,但是,你用外部kill命令杀死进程时,子进程会变成僵尸进程,只有父进程退出后才会退出。网上说在Windows平台下,python有个os.startfile是可以启动外部程序并不阻塞程序的运行,因为我写的Linux环境下,所以该函数不能用。最后问其他朋友,他说可以在system()将输出重定向就可以了,我试了一下,真的可以,所以现在把代码贴出了,也怪自己平常没有怎么钻。

    os.system(processName+" 1>/dev/null 2>/dev/null &")

    程序功能:

    从配置文件读取要监控的进程,对进程实现监控,当监控程序退出时,会自动拉起进程

    第一种方法:

    在后台启动命令如下:setsid ./WatchProcessDog.py -m &

    代码如下:

    #!/usr/bin/python
    #!encoding=utf-8
    
    import ConfigParser
    import sys
    import threading
    import time
    import os
    import commands
    import subprocess
    
    CONFIG_FILE = "WatchDog.ini"
    SECTION="Monitor"
    SECTION_KEY="Process"
    
    class CWatchProcess(threading.Thread):
    	def __init__(self,configFile):
    		threading.Thread.__init__(self)
    		self.thread_stop = False
    		self.boolexist = False
    		self.curPid = os.getpid()
    		self.configFile = configFile
    		cfg = ConfigParser.ConfigParser()
    		try:
    			cfg.read(self.configFile)
    			allprocesses = cfg.get(SECTION,SECTION_KEY)
    			if '#' in allprocesses:
    				position1 = allprocesses.find('#')
    				self.processes = allprocesses[:position1]
    			else:
    				self.processes = allprocesses
    			self.processes = self.processes.strip()
    			self.monitorProcess = self.processes.split(',')
    		except Exception,e:
    			print e
    	def run(self):
    		while not self.thread_stop:
    			for tmpprocees in self.monitorProcess:
    				processname = os.path.basename(tmpprocees)
    				count = commands.getoutput("ps -elf | grep %s | grep -v %s | wc -l" % (processname,"grep"))
    				if 0 == int(count) and "-m" == sys.argv[1]:
    					self.PullProcess(tmpprocees)
    					continue
    				if 0 == int(count) and "-k" == sys.argv[1]:
    					self.boolexist = True
    					continue
    				if 0 != int(count) and "-m" == sys.argv[1]:
    					#print processname+" is started!"
    					continue
    				if 0 != int(count) and "-k" == sys.argv[1]:
    					self.KillProcess(tmpprocees)
    					self.boolexist = True
    					continue
    			if self.boolexist :
    				self.KillSelf()
    			time.sleep(1)
    	def stop(self):
    		self.thread_stop = True
    	def PullProcess(self,processName):
    		os.system(processName+" 1>/dev/null 2>/dev/null &")
    	def KillProcess(self,processName):
    		os.popen("killall %s" % os.path.basename(processName))
    	def KillSelf(self):
    		curNum = commands.getoutput("ps -elf | grep %s | grep -v %s | wc -l " % (sys.argv[0],"grep"))
    		if 1 == curNum:
    			sys.exit()
    		elif 1 < curNum:
    			result = os.popen("ps -elf | grep %s | grep -v %s" % (sys.argv[0],"grep")).readlines()
    			for tmpresult in result:
    				tmplist = tmpresult.split()
    				if int(self.curPid) == int(tmplist[3]):
    					continue
    				else:
    					os.popen("kill %s" % tmplist[3])
    				#tmpcount = len(tmplist)
    		sys.exit()
    def main():
    	count = len(sys.argv)
    	if count != 2:
    		help()
    		sys.exit()
    	if "-m" == sys.argv[1]:
    		processNum = commands.getoutput("ps -elf | grep %s | grep -v %s | wc -l " % (sys.argv[0],"grep"))
    		if 1 < int(processNum):
    			print sys.argv[0],"is running" 
    			sys.exit()
    		print "start monitor processes"
    	elif "-k" == sys.argv[1]:
    		print "kill all processes"
    	else:
    		help()
    		sys.exit()
    def help():
    	print "Usage:"
    	print "./WatchProcessDog.py -m 			---monitor all processes"
    	print "./WatchProcessDog.py -k 			---kill all processes"
    if __name__ == "__main__":
    	main()
    	watchProcess = CWatchProcess(CONFIG_FILE)
    	watchProcess.start()
    	watchProcess.join()

    第二种方法:

    启动:./SqyDaemon.py -m

    代码如下:

    #!/usr/bin/env python
    #!encoding=utf-8
    
    import sys, os, time, atexit, string,ConfigParser,commands,subprocess
    from signal import SIGTERM 
    
    PID_FILE = "./SqyDaemon.pid"
    CONFIG_FILE = "SqyDaemon.ini"
    SECTION="Monitor"
    SECTION_KEY="Process"
    
    class Daemon:
    	def __init__(self,configFile,pidfile):
    		self.pidfile = pidfile
    		self.configFile = configFile
    		cfg = ConfigParser.ConfigParser()
    		try:
    			cfg.read(self.configFile)
    			allprocesses = cfg.get(SECTION,SECTION_KEY)
    			if '#' in allprocesses:
    				position1 = allprocesses.find('#')
    				self.processes = allprocesses[:position1]
    			else:
    				self.processes = allprocesses
    			self.processes = self.processes.strip()
    			self.monitorProcess = self.processes.split(',')
    		except Exception,e:
    			print e
    	def _daemonize(self):
    		try: 
    			pid = os.fork() 
    			if pid > 0:
    				sys.exit(0)				#退出主进程 
    		except OSError, e:
    			print "fork failed!\nError is:",e.strerror
    			sys.exit(1)
    		os.setsid() 
    		os.umask(0) 
    		#创建子进程
    		try: 
    			pid = os.fork()
    			if pid > 0:
    				sys.exit(0) 
    		except OSError, e: 
    			print "fork failed!\nError is:",e.strerror
    			sys.exit(1) 
    		#创建processid文件
    		atexit.register(self.delpid)
    		pid = str(os.getpid())
    		file(self.pidfile,'w+').write('%s\n' % pid)
    	def delpid(self):
    		os.remove(self.pidfile)
    	def start(self):
    		#检查pid文件是否存在以探测是否存在进程
    		try:
    			pf = file(self.pidfile,'r')
    			pid = int(pf.read().strip())
    			pf.close()
    		except IOError:
    			pid = None
    		if pid:
    			print "pidfile %s already exist. SqyDaemon already running?\n" % self.pidfile
    			sys.exit(1)
    		#启动监控
    		self._daemonize()
    		self._run()
    	def stop(self):
    		#从pid文件中获取pid
    		try:
    			pf = file(self.pidfile,'r')
    			pid = int(pf.read().strip())
    			pf.close()
    		except IOError:
    			pid = None
    		if not pid:
    			if "-r" == sys.argv[1]:
    				print "SqyDaemon restart and monitor related process!"
    			else :
    				message = 'pidfile %s does not exist. SqyDaemon not running?\n'
    				sys.stderr.write(message % self.pidfile)
    			return #重启不报错
    		elif "-r" == sys.argv[1]:
    			print "%s is runing,now restart!" % sys.argv[0]
    		elif "-k" == sys.argv[1]:
    			print "all processes are killed!"
    		#杀进程
    		try:
    			while 1:
    				os.kill(pid, SIGTERM)
    				time.sleep(0.1)
    				for tmpprocees in self.monitorProcess:
    					processname = os.path.basename(tmpprocees)
    					os.system("killall %s" % processname)
    		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)
    	def restart(self):
    		self.stop()
    		self.start()
    	def _run(self):
    		while True:
    			for tmpprocees in self.monitorProcess:
    				processname = os.path.basename(tmpprocees)
    				fullpath = os.path.abspath(tmpprocees)
    				count = commands.getoutput("ps -elf | grep %s | grep -v %s | wc -l" % (processname,"grep"))
    				if 0 == int(count):
    					os.system(tmpprocees+" 1>/dev/null 2>/dev/null &") #标准输出和错误输出重定向到/dev/null
    				else :
    					continue
    			time.sleep(2)
    def help():
    	print "Usage:"
    	print "%s -m 			---monitor all processes" % sys.argv[0]
    	print "%s -k 			---kill all processes" % sys.argv[0]
    	print "%s -r 			---restart all processes" % sys.argv[0]
    if __name__ == '__main__':
    	daemon = Daemon(CONFIG_FILE,PID_FILE)
    	if len(sys.argv) == 2:
    		if '-m' == sys.argv[1]:
    			daemon.start()
    		elif '-k' == sys.argv[1]:
    			daemon.stop()
    		elif '-r' == sys.argv[1]:
    			daemon.restart()
    		else:
    			print 'Unknown command'
    			help()
    			sys.exit(2)
    		sys.exit(0)
    	else:
    		help()
    		sys.exit(2)
    


关键字