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

 

                       
扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。