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通讯,缓存文件要大小限制。或自己主动清除等。



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


    參考:
  • 相关阅读:
    poj 1789 每个字符串不同的字母数代表两个结点间的权值 (MST)
    poj 1251 poj 1258 hdu 1863 poj 1287 poj 2421 hdu 1233 最小生成树模板题
    poj 1631 最多能有多少条不交叉的线 最大非降子序列 (LIS)
    hdu 5256 最少修改多少个数 能使原数列严格递增 (LIS)
    hdu 1025 上面n个点与下面n个点对应连线 求最多能连有多少条不相交的线 (LIS)
    Gym 100512F Funny Game (博弈+数论)
    UVa 12714 Two Points Revisited (水题,计算几何)
    UVa 12717 Fiasco (BFS模拟)
    UVa 12718 Dromicpalin Substrings (暴力)
    UVa 12716 && UVaLive 6657 GCD XOR (数论)
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/7255605.html
Copyright © 2011-2022 走看看