2012-01-08 86 views
21

当我试着写用C在linux下一个守护进程,我被告知我应该后代码块中添加以下代码:编写Linux守护进程时,为什么必须从tty中分离出来?

/* Preparations */ 
... 

/* Fork a new process */ 
pid_t cpid = fork(); 
if (cpid == -1){perror("fork");exit(1);} 
if (cpid > 0){exit(0);} 

/* WHY detach from tty ? */ 
int fd = open("/dev/tty", O_RDWR); 
ioctl(fd, TIOCNOTTY, NULL); 

/* Why set PGID as current PID ? */ 
setpgid(getpid(), 0); 

我的问题是: 有一个必须做以上操作?

+0

我想部分原因是守护进程不希望写输出或读输入。如果你要开始,例如在SSH会话中使用HTTP服务器,您不会期望会话中的随后的警告输出。 – 2012-01-08 12:48:11

+1

@JohnChadwick你说的确实是你在转换成守护进程时想要做的事情之一,但是通过关闭stdin,stdout和stderr来实现这一点。您从终端上分离以避免某些信号(请参阅下面的答案)。 – 2012-01-08 13:01:22

+1

你可以“不接受”我的回答并接受@ AdamZalcman的代替吗?他比我做得好得多。他对setsid()完全正确,你应该使用它。 – fge 2012-01-08 13:05:55

回答

34

必须从终端撇清你的守护进程,以避免被涉及到终端的操作中发送的信号(如SIGHUP当终端会话结束以及潜在SIGTTIN和SIGTTOU)。

注意然而,从使用TIOCNOTTY ioctl终端解除关联的方式在很大程度上是过时的。您应该改用setsid()

守护进程离开其原始进程组的原因是不接收发送到该组的信号。请注意,setsid()也会将您的流程置于其自己的流程组中。

+2

+1 setsid()' – fge 2012-01-08 13:02:41

+0

+1对于一个非常好的和完整的答案,尤其是“我们为什么要这么做?”部分。 – 2012-01-08 13:10:20

+0

+1。警告:即使在setsid(2)之后,如果不小心(fork()或O_NOCTTY),也可能获取控制终端。 – pilcrow 2012-01-08 16:34:00

10

另一个答案是清楚的,技术上是正确的(所以我相应地upvoted)。

另一个答案是:“不,不要说daemonizes自己写的代码。”

取而代之的是使用一个过程监督框架(如daemontoolsrunitlaunchd)来为您处理此问题。

传统的UNIX服务器是自我守护进程,因此在许多方面都有问题:当前工作目录,进程组和会话独立性,信号掩码和处置,文件系统根目录,权限,umask,打开文件描述符等。

然而,大多数或所有这些过程属性都跨越exec()继承,也就是说一个服务器进程通常可以“生”与所需的进程组,工作目录,根等,这里有一点需要做好自己的一切,尽管你通常仍然需要自己管理特权操作和权限撤销。 (事实上​​,我认为在编写自我后台程序时存在长期风险,并且复制粘贴并且仓促地移植和扩展了锅炉板“后台”程序,程序员花费时间在辅助代码上而不是在程序的主要目的。)

+0

很好的回答!守护进程应该是调用者的选择,而不是应用程序本身强制的选择。而对于调用者来说,有很多现有的工具,不需要在应用程序中重新创建它。 – 2017-02-16 10:50:16