簡體   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