1. 调用fork()以便父进程可以退出,这样就将控制权归还给运行你程序的命令行或shell程序。需要这一步以便保证新进程不是一个进程组头领进程(process group leader)。下一步,‘setsid()’,会因为你是进程组头领进程而失败。
2. 调用‘setsid()’ 以便成为一个进程组和会话组的头领进程。由于一个控制终端与一个会话相关联,而且这个新会话还没有获得一个控制终端,我们的进程没有控制终端,这对于守护程序来说是一件好事。
3. 再次调用‘fork()’所以父进程(会话组头领进程)可以退出。这意味着我们,一个非会话组头领进程永远不能重新获得控制终端。
4. 调用‘chdir("/")’确认我们的进程不保持任何目录于使用状态。不做这个会导致系统管理员不能卸装(umount)一个文件系统,因为它是我们的当前工作目录。 [类似的,我们可以改变当前目录至对于守护程序运行重要的文件所在目录]
5. 调用‘umask(0)’以便我们拥有对于我们写的任何东西的完全控制。我们不知道我们继承了什么样的umask。 [这一步是可选的](译者注:这里指步骤5,因为守护程序不一定需要写文件)
6. 调用‘close()’关闭文件描述符0,1和2。这样我们释放了从父进程继承的标准输入,标准输出,和标准错误输出。我们没办法知道这些文描述符符可能已经被重定向去哪里。注意到许多守护程序使用‘sysconf()’来确认‘_SC_OPEN_MAX’的限制。‘_SC_OPEN_MAX’告诉你每个进程能够打开的最多文件数。然后使用一个循环,守护程序可以关闭所有可能的文件描述符。你必须决定你需要做这个或不做。如果你认为有可能有打开的文件描述符,你需要关闭它们,因为系统有一个同时打开文件数的限制。
7. 为标准输入,标准输出和标准错误输出建立新的文件描述符。即使你不打算使用它们,打开着它们不失为一个好主意。准确操作这些描述符是基于各自爱好;比如说,如果你有一个日志文件,你可能希望把它作为标准输出和标准错误输出打开,而把‘/dev/null’作为标准输入打开;作为替代方法,你可以将‘/dev/console’作为标准错误输出和/或标准输出打开,而‘/dev/null’作为标准输入,或者任何其它对你的守护程序有意义的结合方法。(译者注:一般使用dup2函数原子化关闭和复制文件描述符。
说实话,上面这段文字看着有点云里雾里,下面看个具体的代码(我只粘贴了函数的第一部分,也是最重要的一部分,要查看整个代码,请移步到这http://www.pythonid.com/bbs/redirect.php?tid=239&goto=lastpost&highlight=自行查看):
01
def
daemonize(stdout
=
'/dev/null'
, stderr
=
None
, stdin
=
'/dev/null'
,
02
pidfile
=
None
, startmsg
=
'started with pid %s'
):
19
if
pid >
0
: sys.exit(
0
)
21
sys.stderr.write(
"fork #1 failed: (%d) %s\n"
%
(e.errno, e.strerror))
30
if
pid >
0
: sys.exit(
0
)
32
sys.stderr.write(
"fork #2 failed: (%d) %s\n"
%
(e.errno, e.strerror))
35
if
not
stderr: stderr
=
stdout
37
so
=
file
(stdout,
'a+'
)
38
se
=
file
(stderr,
'a+'
,
0
)
39
pid
=
str
(os.getpid())
40
sys.stderr.write(
"\n%s\n"
%
startmsg
%
pid)
42
if
pidfile:
file
(pidfile,
'w+'
).write(
"%s\n"
%
pid)
44
os.dup2(si.fileno(), sys.stdin.fileno())
45
os.dup2(so.fileno(), sys.stdout.fileno())
46
os.dup2(se.fileno(), sys.stderr.fileno())
仔细比对前面说的步骤和代码,大体上是没有什么问题了,但是疑问就来了,os.fork()到底是怎么工作的呢,GOOGLE了个遍,最后的结论是这样:
父进程执行代码到os.fork()处时,会将自己整个拷贝一份(即子进程)这时候父进程os.fork()的返回值大于零(即子进程的PID),子进程os.fork()的返回值等于零,父进程结束,子进程继续执行,这时候又遇到第二个os.fork(),如上次一样,原来的子进程变成了父进程,又产生新的子进程,之后父进程就结束。这就能够说通第一次是避免process group leader,第二次是避免session group leader。子进程就变成了一个五终端,无会话的完全自我掌控的后台进程了。