linux提供了一个daemon函数,使得进程能够脱离控制台执行,实现了后台执行的效果。可是进程后台执行后,原本在终端控制台输出的数据就看不到了。
那么,如何才干找回这些数据?
这里。文章主题就环绕着 如何获得后台进程的控制台数据,当中的原理要从daemon说起。
daemon主要做两件事:
1、创建子进程,退出当前进程,而且以子进程创建新会话。这样,就算父进程退出,子进程也不会被关闭
2、将标准输入。标准输出,标准错误都重定向/dev/null
daemon 实现大致例如以下:
int daemonize(int nochdir, int noclose) { int fd; switch (fork()) { case -1: return (-1); case 0: break; default: _exit(EXIT_SUCCESS); } if (setsid() == -1) return (-1); if (nochdir == 0) { if(chdir("/") != 0) { perror("chdir"); return (-1); } } if (noclose == 0 && (fd = open("/dev/null", O_RDWR, 0)) != -1) { if(dup2(fd, STDIN_FILENO) < 0) { perror("dup2 stdin"); return (-1); } if(dup2(fd, STDOUT_FILENO) < 0) { perror("dup2 stdout"); return (-1); } if(dup2(fd, STDERR_FILENO) < 0) { perror("dup2 stderr"); return (-1); } if (fd > STDERR_FILENO) { if(close(fd) < 0) { perror("close"); return (-1); } } } return (0); }
所以,想取回进程的控制台数据,仅仅要将标准输出,标准错误重定向到指定文件,然后读取这个文件就好了。
文章这里写了个样例,简单演示下(这里通过kill信号完毕进程通信,有点粗暴)
代码例如以下,保存为 daemon_example.c
#include <signal.h> #include <unistd.h> #include <stdio.h> #include <fcntl.h> static int fd = -1; void sigroutine(int dunno) { switch (dunno) { case SIGUSR1: fprintf(stderr, "Get a signal -- SIGUSR1 \n"); if (fd != -1) close(fd); fd = open("/tmp/console_temp.log", O_RDWR|O_APPEND|O_CREAT, 0600); if (fd == -1) break; dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); break; case SIGUSR2: fprintf(stderr, "Get a signal -- SIGUSR2 \n"); if (fd != -1) close(fd); fd = open("/dev/null", O_RDWR, 0); if (fd == -1) break; dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); break; } return; } int main() { signal(SIGUSR1, sigroutine); signal(SIGUSR2, sigroutine); daemon(1,0); for (;;){ fprintf(stderr,"test \n") ; // 不断打印test sleep(1); } return 0; }
然后,编译和执行这个程序:
$ gcc -o daemon_example daemon_example.c
$ chmod +x daemon_example
$ ./daemon_example
$ ps -ef| grep daemon_example
root 11328 1 0 19:15 ?
00:00:00 ./daemon_example
如上,进程后台执行了。拿到pid 11328
接着,写个脚本測试这个程序, 保存为test.sh:
#!/bin/bash pid=$1 ps -p $pid>/dev/null if [ ! $? -eq 0 ] ; then echo pid does not exist! exit 1 fi echo pid $pid trap "kill -usr2 $pid && exit 1" HUP INT QUIT TERM kill -usr1 $pid echo it works,please wait.. sleep 1 tail -f -n 0 /tmp/console_temp.log echo done!
执行这个脚本,结果例如以下:
$ ./test.sh 11328
pid 11328
it works,please wait..
test
test
然后,按ctrl+c 退出脚本,这时脚本会通知进程将标准输出和标准错误重定向到 /dev/null。继续后台执行。
这样,这个脚本就成了后台进程的调试工具了,须要后台数据的时候执行一下,不须要就关闭。
当然,这仅仅是一个演示样例。实际应用中要做改善。比方kill信号改成pipe或socket通讯,缓存文件要大小限制。或自己主动清除等。
文章最后。是不是有点取巧。你有什么更好的办法,欢迎评论交流!
參考:
[1] linux获取daemon进程的控制台数据 没有开花的树