gpt4 book ai didi

java - 空字符串解析ntpq命令结果

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:02:43 25 4
gpt4 key购买 nike

我正在解析执行这个复合命令的结果

  ntpq -c peers | awk ' $0 ~ /^*/ {print $9}'

为了获取 Activity ntp服务器的偏移量。

这是定期使用和执行的java代码

 public Double getClockOffset() {
Double localClockOffset = null;

try {

String[] cmd = {"/bin/sh",
"-c",
"ntpq -c peers | awk \' $0 ~ /^\\*/ {print $9}\'"};

Process p = Runtime.getRuntime().exec(cmd);

p.waitFor();

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

String line = buf.readLine();

if (!StringUtils.isEmpty(line)) {
localClockOffset = Double.parseDouble(line.trim());
} else {
// Log "NTP -> Empty line - No active servers - Unsynchronized"
}
} catch (Exception e) {
// Log exception
}

return localClockOffset;
}

ntpq 结果示例

>      remote           refid      st t when poll reach   delay   offset  jitter
> ==============================================================================
> *server001s1 .LOCL. 1 u 33 64 377 0.111 -0.017 0.011
> +server002s1 10.30.10.6 2 u 42 64 377 0.106 -0.006 0.027
> +server003s1 10.30.10.6 2 u 13 64 377 0.120 -0.009 0.016

请注意 awk 搜索以“*”开头的第一行并提取其第九列。在示例中:-0.017

问题是有时我会收到 no-active-servers 日志消息 - 旨在在没有带“*”的服务器时出现 - 而通过控制台执行命令会返回一个数字。

我知道我没有关闭该代码中的 BufferedReader 但这是此行为的原因吗?在每个方法调用中都会创建一个新实例(并在垃圾收集之前保持打开状态),但我认为这不应该是导致此问题的原因。

最佳答案

Runtime.exec() 只是调用其中的 ProcessBuilder,就像这样:

public Process More ...exec(String[] cmdarray, String[] envp, File dir)
throws IOException {
return new ProcessBuilder(cmdarray)
.environment(envp)
.directory(dir)
.start();
}

参见 OpenJDK Runtime.java

因此,使用它代替 ProcessBuilder 没有任何问题。

问题是你调用了:

p.waitFor();

在您获得 InputStream 之前。

这意味着当您获得 InputStream 时,该进程已经终止,并且输出流数据可能对您可用,也可能不可用,具体取决于操作系统缓冲实现的细微差别以及精确的操作时间。

因此,如果您将 waitFor() 移至底部,您的代码应该会开始更可靠地工作。

然而,在 Linux 下,您通常应该能够从 PIPE 缓冲区读取剩余数据,即使在写入过程结束后也是如此。

还有 UNIXProcess OpenJDK 中的实现实际上明确地使用了它,并在进程退出后尝试耗尽剩余数据,以便可以回收文件描述符:

/** Called by the process reaper thread when the process exits. */
synchronized void processExited() {
synchronized (closeLock) {
try {
InputStream in = this.in;
// this stream is closed if and only if: in == null
if (in != null) {
byte[] stragglers = drainInputStream(in);
in.close();
this.in = (stragglers == null) ?
ProcessBuilder.NullInputStream.INSTANCE :
new ByteArrayInputStream(stragglers);
}
} catch (IOException ignored) {}
}
}

这似乎足够可靠,至少在我的测试中是这样,所以很高兴知道您正在运行哪个特定版本的 Linux|Unix 和 JRE。

您是否也考虑过应用程序级问题的可能性?IE。 ntpq 并不能真正保证总是返回 * 行。

所以,最好从管道中删除 awk 部分,看看是否始终会有一些输出。

另一件需要注意的事情是,如果您的 shell 管道步骤之一失败(例如 ntpq 本身),您还将得到一个空输出,因此您还必须跟踪 STDERR(例如通过将其与 STDOUT 合并ProcessBuilder)。

旁注

在开始使用数据之前执行 waitFor 在任何情况下都是一个坏主意,因为如果您的外部进程将产生足够的输出来填充管道缓冲区,它就会挂起等待某人阅读它,这永远不会发生,因为您的 Java 进程将同时被锁定在 waitFor 中。

关于java - 空字符串解析ntpq命令结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46583758/

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