C 为什么在编写linux守护进程时必须与tty分离?

C 为什么在编写linux守护进程时必须与tty分离?,c,linux,terminal,daemon,C,Linux,Terminal,Daemon,当我尝试在linux下使用C编写守护程序时,有人告诉我应该在fork代码块之后添加以下代码: /* 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); i

当我尝试在linux下使用C编写守护程序时,有人告诉我应该在fork代码块之后添加以下代码:

/* 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);
我的问题是:
必须执行上述操作吗?

您必须解除守护进程与终端的关联,以避免发送与终端操作相关的信号(如终端会话结束时的SIGHUP,以及潜在的SIGTTIN和SIGTTOU)

然而,请注意,使用TIOCNOTTY
ioctl
与终端解除关联的方式基本上已经过时。你应该改用


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

另一个答案是明确的,技术上是正确的(因此我相应地投了赞成票)

另一个答案是:“不,不要编写将自身后台监控的代码。”

取而代之的是使用一个过程监督框架(比如or)来为您解决这个问题

传统的UNIX服务器是自我监控的,因此会对许多事情产生麻烦:当前工作目录、进程组和会话独立性、信号掩码和配置、文件系统根目录、权限、umask、打开文件描述符等

但是,大多数或所有这些进程属性都是跨继承的,这意味着服务器进程通常可以“天生”具有所需的进程组、工作目录、根目录等。几乎不需要自己做任何事情,尽管您通常仍然需要自己管理特权操作和特权撤销


(事实上,我认为编写自我监控程序存在长期风险。样板“后台”例程会被复制、粘贴、匆忙移植和扩展,程序员将时间花在辅助代码上,而不是花在程序的主要用途上。)

我认为部分原因是守护进程不需要写入输出或读取输入。如果您要启动,例如SSH会话上的HTTP服务器,您不会期望稍后在会话中出现随机警告输出。@JohnChadwick您所说的确实是您在转换为守护进程时想要做的事情之一,但是您可以通过关闭stdin、stdout和stderr来实现这一点。您可以从终端分离以避免某些信号(参见下面的答案)。您可以“不接受”我的答案并接受@AdamZalcman的答案吗?他比我做得好得多。他对setsid()的看法完全正确,你应该使用它。@AdamZalcman哦,对了,我实际上忘记了关闭std*。我在想,更改进程组ID会阻止所有相关信号,但这样做的意义要小得多,至少在SIGHUP的情况下是这样的。+1。警告:即使在设置了ID(2)之后,如果不小心的话,也有可能获得一个控制终端(fork()或O_NOCTTY)。你能详细说明一下吗?为什么后台进程不能忽略这些信号?回答得很好!Daemoning应该由调用方选择,而不是由应用程序本身强制执行。对于调用者来说,有很多现有的工具,不需要在应用程序中重新发明。