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
#include
#include
#include
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
按ctrl+c 退出脚本,这时脚本会通知进程将标准输出和标准错误重定向到 /dev/null,继续后台运行。
[root@iZ25dcp92ckZ testdemo]# sh -x ./test.sh 16935
+ pid=16935
+ ps -p 16935
+ '[' '!' 0 -eq 0 ']'
+ echo pid 16935
pid 16935
+ trap 'kill -usr2 16935 && exit 1' HUP INT QUIT TERM
+ kill -usr1 16935
+ echo it works,please wait..
it works,please wait..
+ sleep 1
+ tail -f -n 0 /tmp/console_temp.log
test
test
test
test
==========================================================
接着,写个脚本测试这个程序, 保存为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通讯,缓存文件要限制大小,或自动清除等。
摘自:http://blog.csdn.net/mycwq/article/details/50479735
这里,文章主题就围绕着 如何获得后台进程的控制台数据,其中的原理要从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
#include
#include
#include
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
按ctrl+c 退出脚本,这时脚本会通知进程将标准输出和标准错误重定向到 /dev/null,继续后台运行。
[root@iZ25dcp92ckZ testdemo]# sh -x ./test.sh 16935
+ pid=16935
+ ps -p 16935
+ '[' '!' 0 -eq 0 ']'
+ echo pid 16935
pid 16935
+ trap 'kill -usr2 16935 && exit 1' HUP INT QUIT TERM
+ kill -usr1 16935
+ echo it works,please wait..
it works,please wait..
+ sleep 1
+ tail -f -n 0 /tmp/console_temp.log
test
test
test
test
==========================================================
接着,写个脚本测试这个程序, 保存为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通讯,缓存文件要限制大小,或自动清除等。
摘自:http://blog.csdn.net/mycwq/article/details/50479735
作者:jackxiang@向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除
地址:https://jackxiang.com/post/8831/
版权所有。转载时必须以链接形式注明作者和原始出处及本声明!
最后编辑: jackxiang 编辑于2016-7-24 15:54
评论列表