[英]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.