c - 向stderr写入数据使程序成为守护进程后退出

标签 c linux unix daemon stderr

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

#include<stdio.h>

int main(int argc, char **argv)
{
         fprintf(stderr, "output 1\n");
         printf("output 2\n");
         fflush(stdout);
         system("echo abc");
         fprintf(stderr, "output 3\n ");
         printf("output 4\n"); 
         fflush(stdout);

         daemon(0, 1);

         fprintf(stderr, "output 5\n");
         printf("output 6\n");
         fflush(stdout);
         system("echo abc");
         fprintf(stderr, "output 7\n");
         printf("output 8\n");
         fflush(stdout);

}

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

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

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

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

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()系统调用导致程序 split 成两个独立的进程。这称为“fork”,可以使用 fork() 系统调用更紧密地控制它。在 fork 之后,两个进程都保留指向打开文件描述符的指针:stdin、stdout 和 stderr。根据“man 3 daemon”,父进程在fork之后调用exit()

当您从 SSH 调用可执行文件时,SSH session 将运行一个进程。它 fork 出一个 child ,然后主进程退出。 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 上),以便 parent 向 child 发送一个 SIGHUP。

关于c - 向stderr写入数据使程序成为守护进程后退出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22295279/

相关文章:

java - 单独进程控制java或linux脚本

无法使用 execl 列出特定目录

unix - 使用 awk 多个字段分隔符,每个字段分隔符出现多次

c - 在Linux终端中使用gcc编译C文件时出错

c - 我如何发送测量温度的字符,以便在我的串行捕获程序中可以查看它(使用 Realterm 或 Putty)

c - 警告 printf 格式不适用于 uint32_t 类型的变量

python - systemd 服务无法启动 bash 脚本

c - 如何在 Dev C++ 中使用像 ╔ ═ 和 ╗ 这样的字符作为字符串的一部分?

go - 即使设置了进程组pid,Go也不会终止基于GUI的进程

shell - 在 shell 终端中输入引号 "会发生什么