设为首页 收藏本站
查看: 699|回复: 0

[经验分享] [转]Python 守护进程

[复制链接]

尚未签到

发表于 2018-8-7 07:13:08 | 显示全部楼层 |阅读模式
  守护进程:通常被定义为一个后台进程,而且它不属于任何一个终端会话(terminal session)。许多系统服务由守护程序实施;如网络服务,打印等。
  下面是转自一位网友写的编写守护进程的步骤:
  1. 调用fork()以便父进程可以退出,这样就将控制权归还给运行你程序的
  命令行或shell程序。需要这一步以便保证新进程不是一个进程组头领进程(process
  group leader)。下一步,‘setsid()’,会因为你是进程组头领进程而失败。
  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函数原子化关闭和复制文件描述符。
  说实话,上面这段文字看着有点云里雾里,下面看个具体的代码(我只粘贴了函数的第一部分,也是最重要的一部分,要查看整个代码,请移步到这http://www.pythonid.com/bbs/redirect.php?tid=239&goto=lastpost&highlight=自行查看):
  def daemonize(stdout='/dev/null', stderr=None, stdin='/dev/null',
  pidfile=None, startmsg = 'started with pid %s' ):
  '''
  This forks the current process into a daemon.
  The stdin, stdout, and stderr arguments are file names that
  will be opened and be used to replace the standard file descriptors
  in sys.stdin, sys.stdout, and sys.stderr.
  These arguments are optional and default to /dev/null.
  Note that stderr is opened unbuffered, so
  if it shares a file with stdout then interleaved output
  may not appear in the order that you expect.
  '''
  # flush io
  sys.stdout.flush()
  sys.stderr.flush()
  # Do first fork.
  try:
  pid = os.fork()
  if pid > 0: sys.exit(0) # Exit first parent.
  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("/")
  os.umask(0)
  os.setsid()
  # Do second fork.
  try:
  pid = os.fork()
  if pid > 0: sys.exit(0) # Exit second parent.
  except OSError, e:
  sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
  sys.exit(1)
  # Open file descriptors and print start message
  if not stderr: stderr = stdout
  si = file(stdin, 'r')
  so = file(stdout, 'a+')
  se = file(stderr, 'a+', 0)  #unbuffered
  pid = str(os.getpid())
  sys.stderr.write("\n%s\n" % startmsg % pid)
  sys.stderr.flush()
  if pidfile: file(pidfile,'w+').write("%s\n" % pid)
  # Redirect standard file descriptors.
  os.dup2(si.fileno(), sys.stdin.fileno())
  os.dup2(so.fileno(), sys.stdout.fileno())
  os.dup2(se.fileno(), sys.stderr.fileno())
  仔细比对前面说的步骤和代码,大体上是没有什么问题了,但是疑问就来了,os.fork()到底是怎么工作的呢,GOOGLE了个遍,最后的结论是这样:
  父进程执行代码到os.fork()处时,会将自己整个拷贝一份(即子进程)这时候父进程os.fork()的返回值大于零(即子进程的PID),子进程os.fork()的返回值等于零,父进程结束,子进程继续执行,这时候又遇到第二个os.fork(),如上次一样,原来的子进程变成了父进程,又产生新的子进程,之后父进程就结束。这就能够说通第一次是避免process group leader,第二次是避免session group leader。子进程就变成了一个无终端,无会话的完全自我掌控的后台进程了。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-547840-1-1.html 上篇帖子: python中的asyncore 下篇帖子: ubuntu下python2-python3版共存,创建django项目出现的问题
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表