前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python 守护进程(daemon)

python 守护进程(daemon)

作者头像
py3study
发布2020-01-10 11:33:55
1.1K0
发布2020-01-10 11:33:55
举报
文章被收录于专栏:python3
代码语言:javascript
复制
守护进程的编写步骤:
1、fork子进程,然后父进程退出,此时子进程会被init进程接管。
2、修改子进程的工作目录,创建新进程组合新会话,修改umask。
3、子进程再次fork一个进程,这个进程可以称为孙子进程,然后子进程退出。
4、重定向孙子进程的标准输入流,标准输出流,标准错误到/dev/null

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import sys, os

'''将当前进程fork为一个守护进程
   注意:如果你的守护进程是由inetd启动的,不要这样做!inetd完成了
   所有需要做的事情,包括重定向标准文件描述符,需要做的事情只有chdir()和umask()了
'''

def daemon(stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
    # 重定向标准文件描述符(默认情况下定向到/dev/null)  
    try:
        pid = os.fork()
        # 父进程(会话组头领进程)退出,这意味着一个非会话组头领进程永远不能重新获得控制终端。  
        if pid > 0:
            sys.exit(0)  # 父进程退出  
    except OSError, e:
        sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
        sys.exit(1)

        # 从母体环境脱离  
    os.chdir("/")  # chdir确认进程不保持任何目录于使用状态,否则不能umount一个文件系统。也可以改变到对于守护程序运行重要的文件所在目录  
    os.umask(0)  # 调用umask(0)以便拥有对于写的任何东西的完全控制,因为有时不知道继承了什么样的umask。  
    os.setsid()  # setsid调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。  

    # 执行第二次fork  
    try:
        pid = os.fork()
        if pid > 0:
            sys.exit(0)  # 第二个父进程退出  
    except OSError, e:
        sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
        sys.exit(1)

        # 进程已经是守护进程了,重定向标准文件描述符  

    for f in sys.stdout, sys.stderr: f.flush()
    si = open(stdin, 'r')
    so = open(stdout, 'a+')
    se = open(stderr, 'a+')
    os.dup2(si.fileno(), sys.stdin.fileno())  # dup2函数原子化关闭和复制文件描述符  
    os.dup2(so.fileno(), sys.stdout.fileno())
    os.dup2(se.fileno(), sys.stderr.fileno())


# 示例函数:每秒打印一个数字和时间戳  
def main():
    import time
    sys.stdout.write('Daemon started with pid %d\n' % os.getpid())
    sys.stdout.write('Daemon stdout output\n')
    sys.stderr.write('Daemon stderr output\n')
    c = 0
    while True:
        sys.stdout.write('%d: %s\n' % (c, time.ctime()))
        sys.stdout.flush()
        c = c + 1
        time.sleep(1)


if __name__ == "__main__":
    daemone('/dev/null', '/tmp/daemon_stdout.log', '/tmp/daemon_error.log')
    main()

# 可以通过命令ps -ef | grep daemon.py查看后台运行的继承
# 在/tmp/daemon_error.log会记录错误运行日志
# 在/tmp/daemon_stdout.log会记录标准输出日志。

1、fork子进程,父进程退出

通常,我们执行服务端程序的时候都会通过终端连接到服务器,成功连接后会加载shell环境,终端盒shell都是进程,shell进程是终端进程的子进程,通过ps命令可以很容易的查看到,在这个shell环境下一开始执行的程序都是shell进程的子进程,自然会受到shell进程的影响,在程序里fork子进程后,父进程退出,对于shell进程来说,这个父进程就算执行完毕,而产生的子进程会被init进程接管,从而也就脱离了终端控制。

2.修改子进程的工作目录

子进程在创建的时候会继承父进程的工作目录,如果执行的程序是在U盘里面,就会导致U盘不能卸载。

3.创建新会话

使用setsid后,子进程就会成为新会话的首进程,子进程会成为新进程组的组长进程,子进程没有控制终端。

4.修改umask

由于umask会屏蔽权限,所有设定为0,这样可以避免读写文件时碰到权限问题

5.fork孙子进程,子进程退出

经过上面几个步骤后,子进程会成为新的进程组老大,可以重新申请打开终端,为了避免这个问题,fork孙子进程处理,

6.重定向孙子进程的标准输入流,标准输出流,标准错误流到/dev/null

因为是守护进程,本身已经脱离了终端,那么标准输入流,标准输入流,标准错误流就没有什么意义了,所以都转向到/dev/null,就是丢弃的意思

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/08/17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档