解释了正确的守护程序行为(来自PEP 3143) [英] Correct daemon behaviour (from PEP 3143) explained
问题描述
我在Python中有一些[针对RPi]的任务,涉及很多sleep
处理:做一些需要一秒钟或两到三秒的事情,然后再等待几分钟或几小时.
我想在那段睡眠时间内将控制权交还给OS(Linux).为此,我应该守护这些任务.一种方法是使用Python的标准守护程序进程库.
I have some tasks [for my RPi] in Python that involve a lot of sleep
ing: do something that takes a second or two or three, then go wait for several minutes or hours.
I want to pass control back to the OS (Linux) in that sleep time. For this, I should daemonise those tasks. One way is by using Python's Standard daemon process library.
但是守护进程并不是那么容易理解.根据 PEP 3143 的原理部分表现良好的守护程序应执行以下操作.
But daemons aren't so easy to understand. As per the Rationale paragraph of PEP 3143, a well behaved daemon should do the following.
- 关闭所有打开的文件描述符.
- 更改当前工作目录.
- 重置文件访问创建掩码.
- 在后台运行.
- 与流程组分离.
- 忽略终端I/O信号.
- 与控制终端解除关联.
- 不要重新获得控制终端.
- 正确处理以下情况:
- 由System V初始化过程开始.
- 通过SIGTERM信号终止守护程序.
- 孩子会产生SIGCLD信号.
- Close all open file descriptors.
- Change current working directory.
- Reset the file access creation mask.
- Run in the background.
- Disassociate from process group.
- Ignore terminal I/O signals.
- Disassociate from control terminal.
- Don't reacquire a control terminal.
- Correctly handle the following circumstances:
- Started by System V init process.
- Daemon termination by SIGTERM signal.
- Children generate SIGCLD signal.
对于像我这样的Linux/Unix新手来说,其中有些很难解释.但是我想知道为什么我要做什么.那么,这个原理背后的原理是什么?
For a Linux/Unix novice like me, some of this is hardly an explanation. But I want to know why I do what I do. So what is the rationale behind this rationale?
推荐答案
PEP 3142从 Unix网络编程("UNP").该书引用或总结了以下解释.在网上很难找到它,并且下载可能是非法的.所以我从图书馆借来的.涉及的页面在第二版,第1卷(1998)中. (PEP指的是第一版,1990年.)
PEP 3142 took these requirements from Unix Network Programming ('UNP') by the late W. Richard Stevens. The explanation below is quoted or summarised from that book. It's not so easily found online, and it may be illegal to download. So I borrowed it from the library. Pages referred to are in the second edition, Volume 1 (1998). (The PEP refers to the first edition, 1990.)
关闭所有打开的文件描述符.
我们关闭从执行守护程序(即外壳程序)的过程继承的所有打开的描述符.[..]一些守护程序打开
/dev/null
进行读写,并将描述符复制到标准输入,标准输出和标准错误中.""We close any open descriptors inherited from the process that executed the daemon (ie the shell). [..] Some daemons open
/dev/null
for reading and writing and duplicate the descriptor to standard input, standard output and standard error."(此"Howdy World" Python守护程序演示了这一点.)
"这保证了公共描述符是打开的,并且从这些描述符中的任何一个读取都返回0(文件末尾),并且内核仅丢弃写入这三个描述符中任何一个的任何内容.打开这些描述符的原因是这样的守护程序调用的任何假定它可以从标准输入读取或写入标准输出或标准错误的库函数都不会失败;或者,某些守护程序打开它们将在运行时写入的日志文件,并将其描述符复制到标准输出和标准错误". (UNP第337页)
"This guarantees that the common descriptors are open, and a read from any of these descriptors returns 0 (End Of File) and the kernel just discards anything written to any of these three descriptors. The reason for opening these descriptors is so that any library function called by the daemon that assumes it can read from standard input or write to standard output or standard error, will not fail. Alternately, some daemons open a log file that they will write to while running and duplicate its descriptor to standard output and standard error". (UNP p. 337)
更改当前工作目录
打印机守护程序可能会更改为打印机的假脱机目录,并在其中执行所有工作.[...]守护程序可能已在文件系统中的任何位置启动,如果保留在该文件系统中,则无法卸载该文件系统. " (UNP p 337)
"A printer daemon might change to the printer's spool directory, where it does all its work. [...] The daemon could have been started anywhere in the filesystem, and if it remains there, that filesystem cannot be unmounted." (UNP p 337)
为什么要卸载文件系统?两个原因:
1.您想从专用于OS的目录中分离(并能够挂载和卸载)可以填充用户数据的目录.
2.如果从USB记忆棒启动守护程序,则希望能够卸载该记忆棒而不干扰守护程序.Why would you want to unmount a filesystem? Two reasons:
1. You want to separate (and be able mount and unmount) directories that can fill up with user data from directories dedicated to the OS.
2. If you start a daemon from, say, a USB-stick, you want to be able to unmount that stick without interfering with the daemon.重置文件访问创建掩码.
因此,如果守护程序创建自己的文件,则继承文件模式创建掩码中的权限位不会影响新文件的权限位." (UNP,p 337)
"So that if the daemon creates its own files, permission bits in the inherited file mode creation mask do not affect the permission bits of the new files." (UNP, p 337)
在后台运行.
根据定义,Run in the background.
By definition,守护程序是在后台运行并且独立于所有终端的控制的进程". (UNP p 331)
"a daemon is a process that runs in the background and is independent of control from all terminals". (UNP p 331)
与流程组解除关联.
为了理解这一点,您需要了解什么是流程组,这意味着您需要知道fork
的作用.Disassociate from process group.
In order to understand this, you need to understand what a process group is, and that means you need to know whatfork
does.叉子的作用
fork
是创建新进程的唯一方法(在Unix中). (在Linux中,还有clone
).理解fork
的关键在于,它在被调用时(一次)返回两次:一次在调用过程中(=父级),具有新创建的过程的ID(=子级),一次在这个孩子. 当派生返回时,父级在分叉时已知的所有描述符都将与子级共享." (UNP p 102). 当一个进程要执行另一个程序时,它将通过调用fork创建一个新进程,而fork将创建其自身的副本.然后其中一个(通常是孩子)调用新程序. (联合国开发计划署,第102页)fork
is the only way (in Unix) to create a new process. (in Linux, there is alsoclone
). Key in understandingfork
is that it returns twice when called (once): once in the calling process (= parent) with the process ID of the newly created process (= child), and once in the child. "All descriptors known by the parent when forking, are shared with the child when fork returns." (UNP p 102). When a process wants to execute another program, it creates a new process by calling fork, which creates a copy of itself. Then one of them (usually the child) calls the new program. (UNP, p 102)为什么取消与流程组的联系
重点是会话负责人可以获取控制终端.守护程序永远不要这样做,它必须留在后台.这可以通过两次调用
fork
来实现:父叉创建一个孩子,子叉创建一个孙孩子.父母子女被终止,但是孙子女仍然存在.但是因为是孙子,所以不是会话负责人,因此无法获得控制终端. (摘自UNP par 12.4 p 335)The point is that a session leader may acquire a controlling terminal. A daemon should never do this, it must stay in the background. This is achieved by calling
fork
twice: the parent forks to create a child, the child forks to create a grandchild. Parent and child are terminated, but grandchild remains. But because it's a grandchild, it's not a session leader, and therefor can't acquire a controlling terminal. (Summarised from UNP par 12.4 p 335)The double fork is discussed in more detail here, and in the comments below.
忽略终端I/O信号.
从终端键生成的信号不得影响从该终端先前启动的任何守护程序". (UNP第331页)
"Signals generated from terminal keys must not affect any daemons started from that terminal earlier". (UNP p. 331)
与控制终端解除关联,并且不重新获取控制终端.
到目前为止,原因很明显:Disassociate from control terminal and don't reacquire a control terminal.
By now, the reasons are obvious:如果守护程序是从终端启动的,我们希望以后能够使用该终端执行其他任务.例如,如果我们从终端启动该守护程序,请注销该终端,然后再执行其他操作登录该终端,我们不希望在下一个用户的终端会话期间出现任何守护程序错误消息." (UNP p 331)
"If the daemon is started from a terminal, we want to be able to use that terminal for other tasks at a later time. For example, if we start the daemon from a terminal, log off the terminal, and someone else logs in on that terminal, we do not want any daemon error messages appearing during the next user's terminal session." (UNP p 331)
正确处理以下情况:
-
由System V初始化过程启动
- 很显然,守护程序应该在引导时启动.
通过SIGTERM信号终止守护程序
- SIGTERM表示信号终止.在关闭时,init进程通常会将SIGTERM发送给所有进程,通常等待5至20秒,以使它们有时间清理和终止. (UNP,p 135)而且,当父母停止做事时,孩子也可以将SIGTERM发送给父母. (UNP p 408)
孩子会产生SIGCLD信号
- Stevens在讨论SIGCHLD,而不是SIGCLD.它们之间的区别对于了解守护程序的行为并不重要.如果子项终止,则它将SIGCHLD发送给其父项.如果父母没有抓住它,孩子就会变成僵尸(UNP p 118).哦,真有趣.
最后,当我开始在UNP中找到我的问题的答案时,很快就让我感到震惊,我真的应该读更多它.从1998年(!)开始,它有900多个(!)页面,但是我相信UNP中的概念和解释会经受住时间的考验,光彩夺目.史蒂文斯不仅非常了解自己在说什么,而且还了解它的困难之处,并使之更易于理解.真是难得.
On a final note, when I started to find answers to my question in UNP, it soon struck me I really should read more of it. It's 900+ (!) pages, from 1998 (!) but I believe the concepts and the explanations in UNP stand the test of time, gloriously. Stevens not only knew very well what he was talking about, he also understood what was difficult about it, and made it easier to understand. That's really rare.
这篇关于解释了正确的守护程序行为(来自PEP 3143)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!