Python实现Linux下守护进程的编写方法_python

本文实例讲述了Python实现Linux下守护进程的编写方法,分享给大家供大家参考,相信对于大家的Python程序设计会起到一定的帮助作用。具体方法如下:

1. 调用fork()以便父进程可以退出,这样就将控制权归还给运行你程序的命令行或shell程序。需要这一步以便保证新进程不是一个进程组头领进程(process group leader)。下一步,‘setsid()',会因为你是进程组头领进程而失败。进程调用fork函数时,操作系统会新建一个子进程,它本质上与父进程完全相同。子进程从父进程继承了多个值的拷贝,比如全局变量和环境变量。两个进程唯一的区别就是fork的返回值。child(子)进程接收返回值为0,而父进程接收子进程的pid作为返回值。调用fork函数后,两个进程并发执行同一个程序,首先执行的是调用了fork之后的下一行代码。父进程和子进程既并发执行,又相互独立;也就是说,它们是“异步执行”的。

2. 调用‘setsid()' 以便成为一个进程组和会话组的头领进程。由于一个控制终端与一个会话相关联,而且这个新会话还没有获得一个控制终端,我们的进程没有控制终端,这对于守护程序来说是一件好事。

3. 再次调用‘fork()'所以父进程(会话组头领进程)可以退出。这意味着我们,一个非会话组头领进程永远不能重新获得控制终端。

4. 调用‘chdir("/")'确认我们的进程不保持任何目录于使用状态。不做这个会导致系统管理员不能卸装(umount)一个文件系统,因为它是我们的当前工作目录。 [类似的,我们可以改变当前目录至对于守护程序运行重要的文件所在目录]

5. 调用‘umask(0)'以便我们拥有对于我们写的任何东西的完全控制。我们不知道我们继承了什么样的umask。 [这一步是可选的](译者注:这里指步骤5,因为守护程序不一定需要写文件)

6. 调用‘close()'关闭文件描述符0,1和2。这样我们释放了从父进程继承的标准输入,标准输出,和标准错误输出。我们没办法知道这些文描述符符可能已经被重定向去哪里。注意到许多守护程序使用‘sysconf()'来确认‘_SC_OPEN_MAX'的限制。‘_SC_OPEN_MAX'告诉你每个进程能够打开的最多文件数。然后使用一个循环,守护程序可以关闭所有可能的文件描述符。你必须决定你需要做这个或不做。如果你认为有可能有打开的文件描述符,你需要关闭它们,因为系统有一个同时打开文件数的限制。

7. 为标准输入,标准输出和标准错误输出建立新的文件描述符。即使你不打算使用它们,打开着它们不失为一个好主意。准确操作这些描述符是基于各自爱好;比如说,如果你有一个日志文件,你可能希望把它作为标准输出和标准错误输出打开,而把‘/dev/null'作为标准输入打开;作为替代方法,你可以将‘/dev/console'作为标准错误输出和/或标准输出打开,而‘/dev/null'作为标准输入,或者任何其它对你的守护程序有意义的结合方法。(译者注:一般使用dup2函数原子化关闭和复制文件描述符。

实现代码如下:

# Core modules
importatexit
importos
importsys
importtime
importsignal
classDaemon(object):
  """
A generic daemon class.
Usage: subclass the Daemon class and override the run() method
"""
  def __init__(self, pidfile, stdin=os.devnull,
         stdout=os.devnull, stderr=os.devnull,
         home_dir='.', umask=022, verbose=1):
    self.stdin = stdin
    self.stdout = stdout
    self.stderr = stderr
    self.pidfile = pidfile
    self.home_dir = home_dir
    self.verbose = verbose
    self.umask = umask
    self.daemon_alive = True
  def daemonize(self):
    """
Do the UNIX double-fork magic, see Stevens' "Advanced
Programming in the UNIX Environment" for details (ISBN 0201563177)
"""
    try:
      pid = os.fork()
      if pid > 0:
        # Exit first parent
        sys.exit(0)
    except OSError, e:
      sys.stderr.write(
        "fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
      sys.exit(1)
    # Decouple from parent environment
    os.chdir(self.home_dir)
    os.setsid()
    os.umask(self.umask)
    # Do second fork
    try:
      pid = os.fork()
      if pid > 0:
        # Exit from second parent
        sys.exit(0)
    except OSError, e:
      sys.stderr.write(
        "fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
      sys.exit(1)
    if sys.platform != 'darwin': # This block breaks on OS X
      # Redirect standard file descriptors
      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 = so
      os.dup2(si.fileno(), sys.stdin.fileno())
      os.dup2(so.fileno(), sys.stdout.fileno())
      os.dup2(se.fileno(), sys.stderr.fileno())
    def sigtermhandler(signum, frame):
      self.daemon_alive = False
      signal.signal(signal.SIGTERM, sigtermhandler)
      signal.signal(signal.SIGINT, sigtermhandler)
    if self.verbose >= 1:
      print "Started"
    # Write pidfile
    atexit.register(
      self.delpid) # Make sure pid file is removed if we quit
    pid = str(os.getpid())
    file(self.pidfile, 'w+').write("%s\n" % pid)
  def delpid(self):
    os.remove(self.pidfile)
  def start(self, *args, **kwargs):
    """
Start the daemon
"""
    if self.verbose >= 1:
      print "Starting..."
    # Check for a pidfile to see if the daemon already runs
    try:
      pf = file(self.pidfile, 'r')
      pid = int(pf.read().strip())
      pf.close()
    except IOError:
      pid = None
    except SystemExit:
      pid = None
    if pid:
      message = "pidfile %s already exists. Is it already running?\n"
      sys.stderr.write(message % self.pidfile)
      sys.exit(1)
    # Start the daemon
    self.daemonize()
    self.run(*args, **kwargs)
  def stop(self):
    """
Stop the daemon
"""
    if self.verbose >= 1:
      print "Stopping..."
    # Get the pid from the pidfile
    pid = self.get_pid()
    if not pid:
      message = "pidfile %s does not exist. Not running?\n"
      sys.stderr.write(message % self.pidfile)
      # Just to be sure. A ValueError might occur if the PID file is
      # empty but does actually exist
      if os.path.exists(self.pidfile):
        os.remove(self.pidfile)
      return # Not an error in a restart
    # Try killing the daemon process
    try:
      i = 0
      while 1:
        os.kill(pid, signal.SIGTERM)
        time.sleep(0.1)
        i = i + 1
        if 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):
    """
Restart the daemon
"""
    self.stop()
    self.start()
  def get_pid(self):
    try:
      pf = file(self.pidfile, 'r')
      pid = int(pf.read().strip())
      pf.close()
    except IOError:
      pid = None
    except SystemExit:
      pid = None
    return pid
  def is_running(self):
    pid = self.get_pid()
    print(pid)
    return pid and os.path.exists('/proc/%d' % pid)
  def run(self):
    """
You should override this method when you subclass Daemon.
It will be called after the process has been
daemonized by start() or restart().
"""

感兴趣的读者可以调试运行一下本文实例代码,相信会有新的收获。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索linux
, python
, 守护进程
编写
linux守护进程编写、编写守护进程、shell 编写守护进程、java 编写守护进程、python 守护进程,以便于您获取更多的相关知识。

时间: 2024-08-04 03:32:11

Python实现Linux下守护进程的编写方法_python的相关文章

Linux守护进程的编程方法

守护进程(Daemon)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种很有用的进程.Linux的大多数服务器就是用守护进程实现的.比如,Internet服务器inetd,Web服务器httpd等.同时,守护进程完成许多系统任务.比如,作业规划进程crond,打印进程lpd等.  守护进程的编程本身并不复杂,复杂的是各种版本的Unix的实现机制不尽相同,造成不同Unix环境下守护进程的编程规则并不一致.这需要读者注意,照搬某些书上的规则

浅析Linux守护进程的编程方法教程

守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程.它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程常常在系统引导装入时启动,在系统关闭时终止.Linux系统有很多守护进程,大多数服务都是通过守护进程实现的,同时,守护进程还能完成许多系统任务,例如,作业规划进程crond.打印进程lqd等(这里的结尾字母d就是Daemon的意思). 守护进程的编程本身并不复杂,复杂的是各种版本的Unix的实现机制不尽相同,造成不同Unix

使用Python编写Linux系统守护进程实例_python

守护进程(daemon)是指在UNIX或其他多任务操作系统中在后台执行的电脑程序,并不会接受电脑用户的直接操控.此类程序会被以进程的形式初始化.通常,守护进程没有任何存在的父进程(即PPID=1),且在UNIX系统进程层级中直接位于init之下.守护进程程序通常通过如下方法使自己成为守护进程:对一个子进程调用fork,然后使其父进程立即终止,使得这个子进程能在init下运行.–维基百科 守护进程区别于普通用户登陆系统后运行的进程,它是直接由系统初始化,和系统用户没有关系,而用户开启的进程依存与用

python实现linux下使用xcopy的方法

  本文实例讲述了python实现linux下使用xcopy的方法.分享给大家供大家参考.具体如下: 这个python函数模仿windows下的xcopy命令编写,可以用在linux下 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #!

Python MySQLdb Linux下安装笔记

  这篇文章主要介绍了Python MySQLdb Linux下安装笔记,本文分别讲解了快速安装和手动编译安装两种方法,并分别讲解了操作步骤,需要的朋友可以参考下 在家里windows环境下搞了一次 见 python MySQLdb在windows环境下的快速安装.问题解决方式 http://www.jb51.net/article/65746.htm 在公司开发需要,再搞一次,linux下的. 发现用编译的方式安装真的很蛋疼,不过也算见见世面,各种问题......奋斗 这里也有两种方式: A.

python获取Linux下文件版本信息、公司名和产品名的方法_python

本文实例讲述了python获取Linux下文件版本信息.公司名和产品名的方法,分享给大家供大家参考.具体如下: 区别于前文所述.本例是在linux下得到文件版本信息,主要是通过pefile模块解析文件 中的字符串得到的.代码如下: def _get_company_and_product(self, file_path): """ Read all properties of the given file return them as a dictionary. @retur

解决Linux下php-fpm进程过多导致内存耗尽问题

最近,发现个人博客的Linux服务器,数据库服务经常挂掉,导致需要重启,才能正常访问,极其恶心,于是决心开始解决问题,解放我的时间和精力(我可不想经常出问题,然后人工重启,费力费时). 分析问题 发现问题以后,首先使用 free -m 指令查看当前服务器执行状况: 可以看到我的服务器内存是2G的,但是目前可用内存只剩下70M,内存使用率高达92%,很有可能是内存使用率过高导致数据库服务挂断. 继续看详细情况,使用 top 指令: 然后再看指令输出结果中详细列出的进程情况,重点关注第10列内存使用

在Linux下开发GUI程序的方法

在Linux下开发GUI程序的方法有很多,比如Gnome桌面使用GTK+作为默认的图形界面库,KDE桌面使用Qt作为默认的图形界面库,wxWidgets则是另一个使用广泛的图形库,此外使用Java中的Swing/AWT组件也可以用于开发Linux下的GUI应用. 本文将依次介绍GTK+.Qt.wxWidgets和Swing/AWT,对其进行对比分析. 1. GTK+ 平台支持 虽然GTK+最初是为X Window系统开发的,但是目前已经发展成为一个跨平台的图形界面API,其支持的平台包括: Li

python MySQLdb Windows下安装教程及问题解决方法

  这篇文章主要介绍了python MySQLdb Windows下安装教程及问题解决方法,本文讲解了安装数据库mysql.安装MySQLdb等步骤,需要的朋友可以参考下 使用python访问mysql,需要一系列安装 linux下MySQLdb安装见 Python MySQLdb在Linux下的快速安装 http://www.jb51.net/article/65743.htm ----------------------------------------------------------