当前位置: 首页 > 科技观察

python做服务器时守护进程的实现方法

时间:2023-03-12 08:09:37 科技观察

说说我在需要做守护进程的时候是如何进化到高端的。(有多高端,自己定义吧,我的土,也许是你的高端)Pythondeamon的思路:1.进程与父进程和终端绑定分离。如果不是,则主进程退出,派生子进程跟着倒霉。离开航站楼也是如此。2.进程唯一性保证,这是废话3.标准的输入/输出/错误重定向,为了防止错误打到前面,更好的分析数据。说的洋风点、nb点、细化点(其实就是os的三个动作):os.chdir("/")将当前工作目录更改为根目录。从父进程继承的当前工作目录可能位于已挂载的文件系统中。os.setsid()调用setsid创建一个新的session,创建一个独立于当前session的进程。os.umask(0)重置文件创建掩码。子进程将继承父进程的所有权限。您可以通过调用此方法将文件创建掩码初始化为系统默认值。记得最开始是用shell的方式,把nohup重定向到一个日志文件。怎么用,想必大家都知道吧。nohupxxxxxxxx&然后使用python的subprocess模块??fork守护进程,然后自己退出。这也实现了守护进程。subprocessspawn一个子进程后,仍然可以有效的控制子进程,比如kill或者hang。importsubprocess#xiaorui.ccfromsubprocessimportcallf=open("/dev/null",'r')proc=subprocess.Popen(xxx,shell=True,stdout=f,executable='/bin/bash')f.close学习当twisted是python服务器端的强大工具时,它也可以作为一个等待进程。当然,该方法有一定的局限性,只适用于基于twisted的网络编程。#!/usr/bin/twistd-y#xiaoui.c??cfromtwisted.applicationimportservice,internetfromtwisted.internetimportreactorimporttimeimportos,sysi=0defwritedata():globalii+=1a=iprint'waitingtowritedata(%d)'%一次。sleep(8)print'writingdata!!!!(%d)'%awhileTrue:time.sleep(0.2)aa=time.strftime('%Y-%m-%d%H:%M:%S',time.localtime())os.system("echo%s>>log"%aa)defwriteinthread():reactor.callInThread(writedata)application=service.Application('timeserver')tservice=internet.TimerService(10000,writeinthread)tservice.setServiceParent(application)上面介绍了很多方法,但是python、golang、ruby社区大多使用supervisor进行进程管理。原因很简单明了。supervisor的配置文件还是挺丰富的。他还有一个supervisorctl终端管理器和一个web管理界面。对我来说,supervisortornado是绝配。这段时间发现了一个不错的模块,pipinstalldaemonize这个是我写的daemonizedemo的例子,大家可以直接运行。之后可以看到虽然我死循环了,但是后台的server还在运行,可以通过进程的status获取状态,也可以通过daemonize本身的函数接口获取。#xiaorui.ccfromtimeimportsleepimportos,sysfromdaemonizeimportDaemonizepid="/tmp/test.pid"defwlog():f=open('/tmp/nima','a')f.write('11')f.close()defmain():whileTrue:sleep(5)wlog()daemon=Daemonize(app="test_app",pid=pid,action=main)daemon.start()daemon.get_pid()daemon.is_running()他的源码实际方式:不多说了,就是forkforkfork....#CoremodulesimportatexitimportosimporttimeimportsignalclassDaemon(object):"""Agenericdaemonclass.Usage:subclasstheDaemonclassandoverridetherun()method"""def__init__(self,pidfile,stdin=os.devnull,stdout=os.devnull,stderr=os.devnull,home_dir='.',umask=022,verbose=1):self.stdin=stdinself.stdout=stdoutself.stderr=stderrself.pidfile=pidfileself.home_dir=home_dirself.verbose=verboseself.umask=umaskself.daemon_alive=Truedefdaemonize(self):"""DotheUNIXdouble-forkmagic,seeStevens'"AdvancedProgrammingintheUNIXEnvironment"fordetails(ISBN0201563177)http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16"""try:pid=os.fork()ifpid>0:#Exitfirstparentsys.exit(0)exceptOSError,e:sys.stderr.write("fork#1failed:%d(%s)\n"%(e.errno,e.strerror))sys.exit(1)#Decouplefromparentenvironmentos.chdir(self.home_dir)os.setsid()os.umask(self.umask)#Dosecondforktry:pid=os.fork()ifpid>0:#Exitfromsecondparentsys.exit(0)exceptOSError,e:sys.stderr.write("fork#2failed:%d(%s)\n"%(e.errno,e.strerror))sys.exit(1)ifsys.platform!='darwin':#ThisblockbreaksonOSX#Redirectstandardfiledescriptorssys.stdout.flush()系统。stderr.flush()si=file(self.stdin,'r')so=file(self.stdout,'a+')ifself.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())defsigtermhandler(signum,frame):self.daemon_alive=Falsesignal.signal(signal.SIGTERM,sigtermhandler)signal.signal(signal.SIGINT,sigtermhandler)ifself.verbose>=1:print"Started"#Writepidfileatexit.register(self.delpid)#Makesurepidfileisremovedifwequitpid=str(os.getpid())文件(self).pidfile,'w+').write("%s\n"%pid)defdelpid(self):os.remove(self.pidfile)defstart(self,*args,**kwargs):"""Startthedaemon"""ifself.verbose>=1:print"Starting..."#Checkforapidfiletoseeifthedaemonalreadyrunstry:pf=file(self.pidfile,'r')pid=int(pf.read().strip())pf.close()exceptIOError:pid=NoneexceptSystemExit:pid=Noneifpid:message="pidfile%salreadyexists.Isitalreadyrunning?\n"sys.stderr.write(message%self.pidfile)sys.exit(1)#Startthedaemonself.daemonize()self.run(*args,**kwargs)defstop(self):"""Stopthedaemon"""ifself.verbose>=1:print"Stopping..."#Getthepidfromthepidfilepid=self.get_pid()ifnotpid:message="pidfile%sdoesnotexist.Notrunning?\n"sys.stderr.write(message%self.pidfile)#Justtobesure.AValueErrormightoccurifthePIDfileis#emptybutdoesactuallyexistifos.path.exists(self.pidfile):os.remove(self.pidfile)return#Notanerrorinarestart#Trykillingthedaemonprocesstry:i=0while1:os.kill(pid,signal.SIGTERM)time.sleep(0.1)i=i+1ifi%10==0:os.kill(pid,signal.SIGHUP)exceptOSError,err:err=str(err)iferr.find("Nosuchprocess")>0:ifos.path.exists(self.pidfile):os.remove(self.pidfile)else:printstr(err)sys.exit(1)ifself.verbose>=1:print"Stopped"defrestart(self):"""Restartthedaemon"""self.stop()self.start()defget_pid(self):try:pf=file(self.pidfile,'r')pid=int(pf.read().strip())pf.close()exceptIOError:pid=NoneexceptSystemExit:pid=Nonereturnpiddefis_running(self):pid=self.get_pid()打印(pid)returnpidandos.path.exists('/proc/%d'%pid)defrun(self):"""当你子类守护进程时,你应该覆盖这个方法。它将在进程被start()或restart()守护进程后调用。"""Usingpythonasadaemonizedbystart()orrestart()."""Usingpythonasadaemonizedbystart()orrestart().....原博客:http://rfyiamcool.blog.51cto.com/1030776/1424809