gpt4 book ai didi

java - 运行 linux 命令时 Tomcat 问题

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:31:44 24 4
gpt4 key购买 nike

我正在尝试在 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() 会阻塞,直到可以读取整行(由任何行结束字符序列终止),并且您不会读取该过程的 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());

关于java - 运行 linux 命令时 Tomcat 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26228993/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com