C语言 将数据写入stderr使程序在程序成为守护进程后退出



请看这段代码。它运行在CentOS6 64位。

#include<stdio.h>
int main(int argc, char **argv)
{
         fprintf(stderr, "output 1n");
         printf("output 2n");
         fflush(stdout);
         system("echo abc");
         fprintf(stderr, "output 3n ");
         printf("output 4n"); 
         fflush(stdout);
         daemon(0, 1);
         fprintf(stderr, "output 5n");
         printf("output 6n");
         fflush(stdout);
         system("echo abc");
         fprintf(stderr, "output 7n");
         printf("output 8n");
         fflush(stdout);
}

如果我运行它,我将看到这些消息:

output 1
output 2
abc
output 3
output 4
output 5
output 6
abc
output 7
output 8

如果我使用ssh登录并运行它,我将看到相同的结果。

但是,如果我使用二进制名称作为ssh的参数并运行它,在调用守护进程(0,1)后,程序将在向stderr写入数据时退出。我运行

ssh localhost myapp

我将只看到这些消息:

output 1
output 2
abc
output 3
output 4
output 5
output 6
abc

有人知道为什么吗?根据调试,程序只有在做了三件事后才会退出:

  1. 调用守护进程(0,1).
  2. 调用系统运行另一个应用程序或bash命令。
  3. 写点东西给stderr

非常感谢!

如果您在shell中运行这个命令,您可能会在输出4和输出5之间看到一个新的shell提示符(如果在输出行之间有睡眠,这将更加明显)。

这是因为daemon()系统调用导致程序分裂为两个独立的进程。这被称为"分叉",可以使用fork()系统调用更紧密地控制它。fork之后,两个进程都保留指向打开的文件描述符的指针:stdin、stdout和stderr。根据"man 3 daemon",父进程在fork后调用exit()

当您从SSH调用可执行文件时,SSH会话将运行一个进程。它派生出一个子进程,主进程退出。SSH看到您发出的命令已经完成,因此它关闭SSH连接。这将关闭stdout和stderr。不幸的是,子进程仍有一些工作要做,但它无法写入共享标准错误,因为该文件描述符已关闭。如果您打印更多的调试信息,如printf()fprintf()调用的返回值,您将看到它无法写入已关闭的文件描述符。

如果不是打印到stderr,而是打印到日志文件(大多数守护进程都是这样做的),那么您将看到子进程将继续在后台运行并按照您的期望进行写入。

如果您选择使用fork()而不是daemon(),您可以让父进程等待直到子进程完成。您可以使用pid_t waitpid(pid_t pid, int *stat_loc, int options);

您可能还想查看在父节点和子节点之间发送的信号。当子进程死亡时,它将向父进程发送SIGCHILD。如果您想要反向通知,您可以使用prctl(PR_SET_PDEATHSIG, SIGHUP);设置一个(仅在Linux上),以便父进程向子进程发送SIGHUP。

相关内容

  • 没有找到相关文章

最新更新