zoukankan      html  css  js  c++  java
  • linux获取后台进程的控制台数据

    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 
    ");
    		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 
    ");
    		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 
    ") ; // 不断打印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通讯,缓存文件要大小限制。或自己主动清除等。



    文章最后。是不是有点取巧。你有什么更好的办法,欢迎评论交流!


    參考:
  • 相关阅读:
    安装go版本
    golang简介
    安装MySQL
    art.dialog.art 中,将子页面窗口中的值传递给父框架中
    Windows7下安装CentOS
    生成uuid
    如何开启win7端口的图文教程
    PHPMailer不能发送邮件
    sql 如果关联表 没有值 设置 默认值
    php array 分页
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/7255605.html
Copyright © 2011-2022 走看看