import os import sys from time import sleep try: pid = os.fork() if pid > 0: sys.exit(0) # Exit parent. pid = os.fork()
os.setsid()
os.chdir(self.curdir)
os.umask(022)
if pid > 0: sys.exit(0) # Exit parent. except OSError, e: sys.stderr.write("fork failed: (%d) %s " % (e.errno, e.strerror)) sys.exit(1) while 1: sleep(1)
fork用户将当前进程分叉,即新建一个子进程,这样,运行完pid=os.fork()这条语句后,就有两个进程,这两个进程都会独自运行下面的代码,同时每个进程都有一个pid,子线程的pid为0
派生一个守护进程后,通过while来实现该进程一直在后台运行
.ps -ajx 参数说明:ppid 父进程id,pid 进程id,pgid 进程组id,sid 会话期id
一个进程组包含多个进程,一个会话期包含多个进程组,一个会话期拥有一个终端,
如果在该终端输入退出(ctrl+c)命令,将关闭改会话期包含的所以进程
创建守护进程步骤
目的:使子进程不会拥有控制终端,即不要继承父进程的进程组id和会话组id,也就是使子进程成为进程组组长和会话组组长
1.创建子进程。fork产生子进程,由于有父进程,所以该子进程不会是进程组组长和会话期组长
2.脱离控制终端。通过setid方法,使子进程成为 新的会话期 组长,由于该会话期只有一个进程,所以该子进程也是进程组组长。这是改会话期组长是没有可控制终端的
3.禁止进程重新打开控制终端 。现在,进程已经成为无终端的会话组长,但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端:
4.关闭打开的文件描述符
5.改变当前工作目录
6.重设文件创建掩码
7.从子进程中fork另一个子进程,该子进程不是进程组组长,也不是会话期组长,是真正的守护进程
为了更好地观察创建守护进程中,各种身份的变化,在这里做一个测试
测试代码:
#encoding=utf-8 __author__ = 'kevinlu1010@qq.com' import os import sys from time import sleep try: pid = os.fork() print '完成第一次fork' sleep(10) #sleep1 if pid > 0: sys.exit(0) # Exit first parent. os.setsid() print '执行setsid,使子进程成为会话期组长' sleep(10) #sleep2 os.chdir('/') os.umask(022) #设置当前权限掩码,同时返回先前的权限掩码。 print '完成修改工作目录和权限掩码' sleep(10) #sleep3 pid = os.fork() print '完成第二次fork' sleep(10) #sleep4 if pid > 0: sys.exit(0) # Exit first parent. print '守护进程启动完成' sleep(10) #sleep5 except OSError, e: sys.stderr.write("fork failed: (%d) %s " % (e.errno, e.strerror)) sys.exit(1) while 1: sleep(1)
这里一共有5个sleep,我在每个sleep都用ps -axj|grep python命令查看进程的id变化,分别为:
标题头:
父进程id 进程id 进程组id 会话期id
进程组或会话期的id与该进程组或会话期的组长的进程id相同
例如进程id是7000的进程,它的进程组id是6000,即7000所属的进程组的id是6000,该进程组的组长是进程id为6000的进程,会话期同理
sleep1:
第一个进程为父进程,第二个为子进程,他们有共同的进程组id和会话期id
sleep2:
父进程退出,剩下子进程,通过setsid命令,使子进程成为进程组组长和会话期组长
sleep3:
这个步骤id不会变化
sleep4:
子进程再fork一个子进程,之前的子进程变成父进程,父进程与子进程拥有共同的进程组id和会话期id,
sleep5:
父进程退出,子进程既不是进程组组长也不是会话期组长,子进程与第一个父进程完全脱离关系,子进程没有控制终端,达到守护进程需要的条件