用python做服务端时实现守候进程的那些方式

说说,需要做守候进程的时候,我是怎么进化高端的。(怎么高端,具体自己定义,我的土,说不定是你的高端)

成都创新互联公司从2013年成立,先为湘乡等服务建站,湘乡等地企业,进行企业商务咨询服务。为湘乡企业网站制作PC+手机+微官网三网同步一站式服务解决您的所有建站问题。

python deamon的思路:

1.进程脱离父进程及终端绑定,如果不这样的话,主进程退出,派生的子进程也跟着倒霉了。脱离终端也是这个理。

2.进程唯一性保证,这是废话

3.标准输入/输出/错误重定向,为了不让错误打到前面,又为了更好的分析数据。

说的洋气点、nb点、细化点(其实就os的三个动作):

os.chdir("/")  将当前工作目录更改为根目录。从父进程继承过来的当前工作目录可能在一个装配的文件系统中。

os.setsid() 调用 setsid 以创建一个新对话期,创建了一个独立于当前会话的进程。

os.umask(0) 重设文件创建掩码,子进程会从父进程继承所有权限,可以通过调用这个方法将文件创建掩码初始化成系统默认。

记得最一开始,用的还是shell的手段,nohup 重定向到一个log文件里面。  具体怎么用,我估计大家都懂。

nohup xxxx  xxxx &

紧接着用python的subprocess模块,来fork daemon进程,然后自己退出来。  这样也是实现了守候进程。 subprocess  派生了子进程后,他还是可以有效的控制子进程,比如kill,挂起。

 
 
  1. import subprocess 
  2. #xiaorui.cc 
  3. from subprocess import call 
  4. f=open("/dev/null",'r') 
  5. proc=subprocess.Popen(xxx, shell=True,stdout=f,executable='/bin/bash') 
  6. f.close

学习python的服务端一大利器 twisted的时候,他本身也可以做守候进程的。当然方法有些局限,仅仅适合依照twisted为左右的网络编程。

 
 
  1. #!/usr/bin/twistd -y 
  2. #xiaorui.cc 
  3. from twisted.application import service, internet 
  4. from twisted.internet import reactor 
  5. import time 
  6. import os,sys 
  7. i=0
  8. def writedata(): 
  9.     global i 
  10.     i+=1
  11.     a=i 
  12.     print 'waiting to write data     (%d)'%a 
  13.     time.sleep(8) 
  14.     print 'writing data!!!!         (%d)'%a 
  15.     while True: 
  16.         time.sleep(0.2) 
  17.         aa=time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) 
  18.         os.system("echo %s >>log"%aa) 
  19.   
  20.   
  21. def writeinthread(): 
  22.     reactor.callInThread(writedata) 
  23.   
  24.   
  25. application =service.Application('timeserver') 
  26. tservice = internet.TimerService(10000,writeinthread) 
  27. tservice.setServiceParent(application )

上面介绍了很多的方法,但是不管是python、golang、ruby社区用supervisor做进程管理的居多。原因,够简单,够直白。 supervisor配置文件是相当的丰富,他还有supervisorctl 终端管理器,更有web 管理界面 。 对我来说,supervisor tornado 绝配。

这段时间找到了一个好模块,pip install daemonize

这是我写的关于 daemonize demo例子,大家可以直接跑跑。 之后,可以看到,我虽然死循环了,但是后台的服务器还是一直跑着,可以通过进程的状态,或者是通过daemonize本身的函数接口获取状态。

 
 
  1. #xiaorui.cc 
  2. from time import sleep 
  3. import os,sys 
  4. from daemonize import Daemonize 
  5.   
  6. pid = "/tmp/test.pid"
  7.   
  8. def wlog(): 
  9.     f=open('/tmp/nima','a') 
  10.     f.write('11') 
  11.     f.close() 
  12.   
  13. def main(): 
  14.     while True: 
  15.         sleep(5) 
  16.         wlog() 
  17.   
  18. daemon = Daemonize(app="test_app", pid=pid, action=main) 
  19. daemon.start() 
  20. daemon.get_pid() 
  21. daemon.is_running()

他的源码实现方式:

不多说了,就是fork fork fork ....

 
 
  1. # Core modules 
  2. import atexit 
  3. import os 
  4. import sys 
  5. import time 
  6. import signal 
  7.   
  8.   
  9. class Daemon(object): 
  10.     """ 
  11.     A generic daemon class. 
  12.   
  13.     Usage: subclass the Daemon class and override the run() method 
  14.     """
  15.     def __init__(self, pidfile, stdin=os.devnull, 
  16.                  stdout=os.devnull, stderr=os.devnull, 
  17.                  home_dir='.', umask=022, verbose=1): 
  18.         self.stdin = stdin 
  19.         self.stdout = stdout 
  20.         self.stderr = stderr 
  21.         self.pidfile = pidfile 
  22.         self.home_dir = home_dir 
  23.         self.verbose = verbose 
  24.         self.umask = umask 
  25.         self.daemon_alive = True
  26.   
  27.     def daemonize(self): 
  28.         """ 
  29.         Do the UNIX double-fork magic, see Stevens' "Advanced 
  30.         Programming in the UNIX Environment" for details (ISBN 0201563177) 
  31.         http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 
  32.         """
  33.         try: 
  34.             pid = os.fork() 
  35.             if pid > 0: 
  36.                 # Exit first parent 
  37.                 sys.exit(0) 
  38.         except OSError, e: 
  39.             sys.stderr.write( 
  40.                 "fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) 
  41.             sys.exit(1) 
  42.   
  43.         # Decouple from parent environment 
  44.         os.chdir(self.home_dir) 
  45.         os.setsid() 
  46.         os.umask(self.umask) 
  47.   
  48.         # Do second fork 
  49.         try: 
  50.             pid = os.fork() 
  51.             if pid > 0: 
  52.                 # Exit from second parent 
  53.                 sys.exit(0) 
  54.         except OSError, e: 
  55.             sys.stderr.write( 
  56.                 "fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) 
  57.             sys.exit(1) 
  58.   
  59.         if sys.platform != 'darwin':  # This block breaks on OS X 
  60.             # Redirect standard file descriptors 
  61.             sys.stdout.flush() 
  62.             sys.stderr.flush() 
  63.             si = file(self.stdin, 'r') 
  64.             so = file(self.stdout, 'a+') 
  65.             if self.stderr: 
  66.                 se = file(self.stderr, 'a+', 0) 
  67.             else: 
  68.                 se = so 
  69.             os.dup2(si.fileno(), sys.stdin.fileno()) 
  70.             os.dup2(so.fileno(), sys.stdout.fileno()) 
  71.             os.dup2(se.fileno(), sys.stderr.fileno()) 
  72.   
  73.         def sigtermhandler(signum, frame): 
  74.             self.daemon_alive = False
  75.             signal.signal(signal.SIGTERM, sigtermhandler) 
  76.             signal.signal(signal.SIGINT, sigtermhandler) 
  77.   
  78.         if self.verbose >= 1: 
  79.             print "Started"
  80.   
  81.         # Write pidfile 
  82.         atexit.register( 
  83.             self.delpid)  # Make sure pid file is removed if we quit 
  84.         pid = str(os.getpid()) 
  85.         file(self.pidfile, 'w+').write("%s\n" % pid) 
  86.   
  87.     def delpid(self): 
  88.         os.remove(self.pidfile) 
  89.   
  90.     def start(self, *args, **kwargs): 
  91.         """ 
  92.         Start the daemon 
  93.         """
  94.   
  95.         if self.verbose >= 1: 
  96.             print "Starting..."
  97.   
  98.         # Check for a pidfile to see if the daemon already runs 
  99.         try: 
  100.             pf = file(self.pidfile, 'r') 
  101.             pid = int(pf.read().strip()) 
  102.             pf.close() 
  103.         except IOError: 
  104.             pid = None
  105.         except SystemExit: 
  106.             pid = None
  107.   
  108.         if pid: 
  109.             message = "pidfile %s already exists. Is it already running?\n"
  110.             sys.stderr.write(message % self.pidfile) 
  111.             sys.exit(1) 
  112.   
  113.         # Start the daemon 
  114.         self.daemonize() 
  115.         self.run(*args, **kwargs) 
  116.   
  117.     def stop(self): 
  118.         """ 
  119.         Stop the daemon 
  120.         """
  121.   
  122.         if self.verbose >= 1: 
  123.             print "Stopping..."
  124.   
  125.         # Get the pid from the pidfile 
  126.         pid = self.get_pid() 
  127.   
  128.         if not pid: 
  129.             message = "pidfile %s does not exist. Not running?\n"
  130.             sys.stderr.write(message % self.pidfile) 
  131.   
  132.             # Just to be sure. A ValueError might occur if the PID file is 
  133.             # empty but does actually exist 
  134.             if os.path.exists(self.pidfile): 
  135.                 os.remove(self.pidfile) 
  136.   
  137.             return  # Not an error in a restart 
  138.   
  139.         # Try killing the daemon process 
  140.         try: 
  141.             i = 0
  142.             while 1: 
  143.                 os.kill(pid, signal.SIGTERM) 
  144.                 time.sleep(0.1) 
  145.                 i = i + 1
  146.                 if i % 10 == 0: 
  147.                     os.kill(pid, signal.SIGHUP) 
  148.         except OSError, err: 
  149.             err = str(err) 
  150.             if err.find("No such process") > 0: 
  151.                 if os.path.exists(self.pidfile): 
  152.                     os.remove(self.pidfile) 
  153.             else: 
  154.                 print str(err) 
  155.                 sys.exit(1) 
  156.   
  157.         if self.verbose >= 1: 
  158.             print "Stopped"
  159.   
  160.     def restart(self): 
  161.         """ 
  162.         Restart the daemon 
  163.         """
  164.         self.stop() 
  165.         self.start() 
  166.   
  167.     def get_pid(self): 
  168.         try: 
  169.             pf = file(self.pidfile, 'r') 
  170.             pid = int(pf.read().strip()) 
  171.             pf.close() 
  172.         except IOError: 
  173.             pid = None
  174.         except SystemExit: 
  175.             pid = None
  176.         return pid 
  177.   
  178.     def is_running(self): 
  179.         pid = self.get_pid() 
  180.         print(pid) 
  181.         return pid and os.path.exists('/proc/%d' % pid) 
  182.   
  183.     def run(self): 
  184.         """ 
  185.         You should override this method when you subclass Daemon. 
  186.         It will be called after the process has been 
  187.         daemonized by start() or restart(). 
  188.         """

使用python做守候进程服务,不知道还有没有更好点、更霸道的方法。大家有的话,要分享下,咱们一块交流下 ....

博客原文:http://rfyiamcool.blog./1030776/1424809

本文题目:用python做服务端时实现守候进程的那些方式
标题来源:http://www.hantingmc.com/qtweb/news2/397652.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联