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 ?
$ 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進程的控制台數據 沒有開花的樹
