守护进程
程序员文章站
2023-11-09 17:29:58
1.什么是守护进程 守护进程是一类特殊的后台进程,在后台运行,且不受任何终端控制。 2.守护进程为什么要独立于终端 用户使守护进程独立于终端是因为, 在守护进程从一个终端启动的情况下,这同一个终端可能被其他的用户使用。例如,用户从一个终端启动守护进程后退出,然后另外一个人也登录到这个终端。用户不希望 ......
1.什么是守护进程
守护进程是一类特殊的后台进程,在后台运行,且不受任何终端控制。
2.守护进程为什么要独立于终端
用户使守护进程独立于终端是因为, 在守护进程从一个终端启动的情况下,这同一个终端可能被其他的用户使用。例如,用户从一个终端启动守护进程后退出,然后另外一个人也登录到这个终端。用户不希望后者在使用该终端的过程中,接收到守护进程的任何错误信息。同样,由终端键人的任何信号(例如中断信号)也不应该影响先前在该终端启动的任何守护进程的运行。虽然让服务器后台运行很容易(只要shell命令行以&结尾即可),但用户还应该做些工作,让程序本身能够自动进入后台,且不依赖于任何终端。
3.进程、进程组、会话、控制终端之间的关系
进程组:由一个或者多个进程组成,进程组号gid就是这些进程中进程组长的pid;
会话: session
控制终端: 一般就是指shell终端;
4.创建一个守护进程的步骤
4.1 创建子进程
由于守护进程是脱离控制终端的,因此首先创建子进程,终止父进程,之后所有的工作都在子进程中完成,而用户在shell终端里则可以执行其他的命令,从而使得程序以僵尸进程形式运行,在形式上做到了与控制终端的脱离。
4.2 在子进程中创建新的会话
创建新的会话有三个作用: 让进程摆脱原会话的控制、让进程摆脱原进程组的控制和让进程摆脱原控制终端的控制。创建新会话使用的是系统函数setsid。
在调用fork函数时,子进程全盘拷贝父进程的会话期(session,是一个或多个进程组的集合)、进程组、控制终端等,虽然父进程退出了,但原先的会话期、进程组、控制终端等并没有改变,因此,那还不是真正意义上使两者独立开来。setsid函数能够使进程完全独立出来,从而脱离所有其他进程的控制。
4.3 改变工作目录
使用fork创建的子进程也继承了父进程的当前工作目录。由于在进程运行过程中,当前目录所在的文件系统不能卸载,因此,把当前工作目录换成其他的路径,如“/”或“/tmp”等。改变工作目录的常见函数是chdir。
4.4 重设文件创建掩码
文件创建掩码是指屏蔽掉文件创建时的对应位。由于使用fork函数新建的子进程继承了父进程的文件创建掩码,这就给该子进程使用文件带来了诸多的麻烦。因此,把文件创建掩码设置为0,可以大大增强该守护进程的灵活性。
5.创建守护进程的实例
1 def becamedaemon(): 2 # 转换为守护进程 3 if platform.system().lower() == 'linux': 4 # do the unix double-fork magic, see stevens' "advanced 5 # programming in the unix environment" for details (isbn 0201563177) 6 try: 7 pid = os.fork() 8 if pid > 0: 9 # exit first parent 退出第一个父进程 10 sys.exit(0) 11 except oserror as e: 12 print("fork #1 failed: {}".format(e)) 13 return false 14 # decouple from parent environment 15 os.chdir("/") # 切换目录 16 os.setsid() # 新建会话 17 os.umask(0) # 重设文件创建掩码 18 # do second fork 19 try: 20 pid = os.fork() 21 if pid > 0: 22 # exit from second parent, print eventual pid before 23 sys.exit(0) # 退出第二个父进程 24 except oserror as e: 25 print("fork #2 failed: {}".format(e)) 26 return false 27 # 重定向标准输入流、标准输出流、标准错误 28 sys.stdout.flush() 29 sys.stderr.flush() 30 si = open("/dev/null", 'r') 31 so = open("/dev/null", 'a+') 32 se = open("/dev/null", 'ab+', 0) 33 os.dup2(si.fileno(), sys.stdin.fileno()) 34 os.dup2(so.fileno(), sys.stdout.fileno()) 35 os.dup2(se.fileno(), sys.stderr.fileno()) 36 else: 37 print("log srv switch to daemon process only valid in linux.") 38 return true