当我尝试使用C在linux下编写守护进程时,我被告知我应该在 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);
我的问题是: 是否有必要进行上述操作?
答案 0 :(得分:41)
您必须取消守护进程与终端的关联,以避免发送与终端操作相关的信号(如终端会话结束时的SIGHUP以及可能的SIGTTIN和SIGTTOU)。
但请注意,使用TIOCNOTTY ioctl
与终端取消关联的方式已基本上已过时。您应该使用setsid()
代替。
守护程序离开其原始进程组的原因是不接收发送到该组的信号。请注意,setsid()
也会将您的流程置于其自己的流程组中。
答案 1 :(得分:13)
另一个答案是清楚的,技术上是正确的(所以我相应地投了赞成票)。
另一个答案是:“不,不要编写守护自己的代码。”
而是使用过程监督框架(如daemontools或runit或launchd)来处理此问题。
传统的UNIX服务器是自我守护的,因此可以解决许多问题:当前工作目录,进程组和会话独立性,信号掩码和处置,文件系统root,特权,umask,打开文件描述符等。
但是,大多数或所有这些进程属性都是通过exec()
继承的,这意味着服务器进程通常可以“生成”所需的进程组,工作目录,root等。几乎没有必要尽管你经常仍然需要自己管理特权操作和特权撤销,但你自己也要做好一切。
(事实上,我认为编写自我守护程序存在长期风险。锅炉板“后台”程序被复制并粘贴并匆忙移植和扩展,程序员花时间在辅助代码而不是程序上主要目的。)