欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

守护进程

程序员文章站 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