繁体   English   中英

运行Linux命令时的Tomcat问题

[英]Tomcat issue while running a linux command

我试图在Java代码中运行linux命令。 该命令是raspivid,我将其放置在test.sh文件下的服务器上以进行实时摄像机流传输。 一切正常,但问题是启动tomcat服务器后几分钟后流停止。 就像流在Java中运行命令的6-7分钟后停止一样,但是在后台运行raspivid进程。 另一方面,当我运行相同的命令而不使用Java代码时,它运行良好。 这是tomcat堆问题还是其他阻止流式传输的问题? 请帮助查看以下代码:

try {
         Process p = Runtime.getRuntime().exec(new String[]{"sudo","sh","/home/pi/test.sh"});
            BufferedReader stdInput = new BufferedReader(new
                 InputStreamReader(p.getInputStream()));

            BufferedReader stdError = new BufferedReader(new
                 InputStreamReader(p.getErrorStream()));

            // read the output from the command
            LOGGER.info("Here is the standard output of the command:\n");
            while ((s = stdInput.readLine()) != null) {
                LOGGER.info(s);
            }

            // read any errors from the attempted command
            LOGGER.info("Here is the standard error of the command (if any):\n");
            while ((s = stdError.readLine()) != null) {
                LOGGER.info(s);
            }

        }

问题是BufferedReader.readLine()阻塞,直到可以读取整行(由任何行末字符序列终止BufferedReader.readLine()为止,并且您不读取进程“并行”的2个输出,如果缓冲区的缓冲区已满,则不读取该2个输出。该过程被阻止。

您需要读取过程输出的数据。

一个进程有2个输出流:标准输出和错误输出。 您必须阅读两者,因为该过程可能会写入这两个输出。

流程的输出流具有缓冲区。 如果输出流的缓冲区已满,则尝试通过该进程向其写入更多数据的尝试将被阻止。

做这样的事情:

BufferedReader stdInput = new BufferedReader(
        new InputStreamReader(p.getInputStream()));

BufferedReader stdError = new BufferedReader(
        new InputStreamReader(p.getErrorStream()));

while (p.isAlive()) {
    while (stdInput.ready())
        LOGGER.info(stdInput.readLine());

    while (stdError.ready())
        LOGGER.info(stdError.readLine());

    Thread.sleep(1);
}

此解决方案的问题(并解决):

此解决方案有一个错误。 该过程可能不会在其输出中写满行。 如果是这种情况,则该过程可能仍会挂起,例如,如果在其标准输出中写入了1个字符,则stdInput.readLine()会阻塞(因为它会读取直到遇到换行符),并且该过程还会继续写入它的错误流,当错误流的缓冲区已满时,该过程将被阻止。

因此,最好不要按行而是按字符来读取缓冲区的输出流(当然,这会使记录更加困难):

StringBuilder lineOut = new StringBuilder(); // std out buffer
StringBuilder lineErr = new StringBuilder(); // std err buffer

while (p.isAlive()) {
    while (stdInput.ready()) {
        // Append the character to a buffer or log if it is the line end
        char c = (char) stdInput.read();
        if (c == '\n') {  // On UNIX systems line separator is one char: '\n'
            LOGGER.info(lineOut.toString());
            lineOut.setLength(0);
        }
        else
            lineOut.append(c);
    }

    while (stdError.ready()) {
        // Append the character to a buffer or log if it is the line end
        char c = (char) stdError.read()
        if (c == '\n') {  // On UNIX systems line separator is one char: '\n'
            LOGGER.info(lineErr.toString());
            lineErr.setLength(0);
        }
        else
            lineErr.append(c);
    }

    Thread.sleep(1);
}

替代(更清洁,更简单)的解决方案

或者,您可以启动2个线程,一个线程读取进程的标准输出,而另一个线程读取进程的标准错误。 这可能简化事情:

private static void consumeStream(final InputStream is) {
    new Thread() {
        @Override
        public void run() {
            BufferedReader r = new BufferedReader(new InputStreamReader(is));
            String line;
            while ((line = r.readLine()) != null)
                LOGGER.info(line);
        }
    }.start();
}

并使用它:

consumeStream(p.getInputStream());
consumeStream(p.getErrorStream());

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM