简体   繁体   English

运行Linux命令时的Tomcat问题

[英]Tomcat issue while running a linux command

I am trying to run a linux command in java code. 我试图在Java代码中运行linux命令。 The command is raspivid which I have placed on the server under test.sh file for live camera streaming. 该命令是raspivid,我将其放置在test.sh文件下的服务器上以进行实时摄像机流传输。 Everything works fine but the problem is the streaming stops after some minutes after starting the tomcat server. 一切正常,但问题是启动tomcat服务器后几分钟后流停止。 Like the streaming stops after 6-7 minutes while running the command in java but at the background the raspivid process is running. 就像流在Java中运行命令的6-7分钟后停止一样,但是在后台运行raspivid进程。 On the other hand when I run the same command without using java code it works fine. 另一方面,当我运行相同的命令而不使用Java代码时,它运行良好。 Is this an issue of tomcat heap or anything else which stops the streaming? 这是tomcat堆问题还是其他阻止流式传输的问题? Please help see the below code: 请帮助查看以下代码:

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);
            }

        }

The problem is that BufferedReader.readLine() blocks until a full line (terminated by any line end char sequences) can be read, and you don't read the 2 outputs of the process "parallel", one if its buffer gets filled and the process gets blocked. 问题是BufferedReader.readLine()阻塞,直到可以读取整行(由任何行末字符序列终止BufferedReader.readLine()为止,并且您不读取进程“并行”的2个输出,如果缓冲区的缓冲区已满,则不读取该2个输出。该过程被阻止。

You need to read the data outputted by the process. 您需要读取过程输出的数据。

A process has 2 output streams: standard output and error output. 一个进程有2个输出流:标准输出和错误输出。 You have to read both because the process might write to both of those outputs. 您必须阅读两者,因为该过程可能会写入这两个输出。

The output streams of the process have buffers. 流程的输出流具有缓冲区。 If the buffer of an output stream is filled, attempt to write further data to that by the process is blocked. 如果输出流的缓冲区已满,则尝试通过该进程向其写入更多数据的尝试将被阻止。

Do something like this: 做这样的事情:

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);
}

Problem with this solution (and fixing it): 此解决方案的问题(并解决):

This solution has an error. 此解决方案有一个错误。 The process might not write full lines to its output. 该过程可能不会在其输出中写满行。 If that is the case, the process might still hang for example if it writes 1 character to its standard output then stdInput.readLine() would block (because it reads until a new line character is encountered) and if the process would keep writing to its error stream, when the buffer of the error stream is full, the process would be blocked. 如果是这种情况,则该过程可能仍会挂起,例如,如果在其标准输出中写入了1个字符,则stdInput.readLine()会阻塞(因为它会读取直到遇到换行符),并且该过程还会继续写入它的错误流,当错误流的缓冲区已满时,该过程将被阻止。

So it would be better not to read the output streams of the buffer by lines but by characters (of course this makes logging it harder): 因此,最好不要按行而是按字符来读取缓冲区的输出流(当然,这会使记录更加困难):

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);
}

Alternative (cleaner, more simple) solution 替代(更清洁,更简单)的解决方案

Alternatively you could start 2 threads, one to read the standard output of the process and one to read the standard error of the process. 或者,您可以启动2个线程,一个线程读取进程的标准输出,而另一个线程读取进程的标准错误。 This could simplfy things: 这可能简化事情:

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();
}

And using it: 并使用它:

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

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

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