21

我需要我的软件与 NTP 服务器通信以确定本地时钟偏移。我曾尝试使用 org.apache.commons.net.ntp 包,但在 Windows 上运行时它的实现相当差,因为使用 System.currentTimeMillis() 来确定 NTP 数据包交换前后的时间。你可能知道也可能不知道,这个值只在系统时钟滴答声时更新,在大多数现代 Win2k3 服务器上是 64Hz 或每 15.625ms。这极大地限制了时钟偏移计算的准确性。

Ntpd 使用 CPU 高频定时器在系统时钟节拍之间进行插值,并获得更高的分辨率时间。您知道使用这种技术或类似技术的 Java 实现吗?或者您知道除 Apache 之外的任何其他 NTP 实现吗?

4

5 回答 5

11

support.ntp.org上有一个 NTP Java 实现

于 2009-05-29T09:49:28.523 回答
10

由于这个问题在 Google 上的“Java NTP 客户端”排名很高:

Android 有一个简单 NTP 客户端的漂亮、紧凑的 Apache 许可实现:android.net.SntpClient

需要对其进行修改才能在非 Android java 上运行,但这应该是微不足道的,因为代码大约是 100 行代码加上另外 100 行详细注释,除了 Android 系统时钟之外没有外部依赖项——而且是偶然的,它已经准备好接受相对计时器,nanoTime()因为它已经使用了这样的相对计时器。

于 2013-06-15T09:48:36.753 回答
4

我编写了一个可以使用的 Java 实现(Java 7):SntpClient

于 2014-11-27T17:05:21.893 回答
3

如果您使用的是 Java 5 或更高版本,您可以使用System.nanoTime()来执行更准确的时间偏移测量吗?您必须修改现有的 NTP 代码,但您应该有它的源代码,我不认为这会很困难。

于 2009-05-29T09:47:34.207 回答
2

我知道这是一个老问题,但我注意到所有答案都没有解释如何使用这些库。在这个答案中,我们将展示一个基本的实现及其背后的逻辑。

实现它的一种简单方法是使用Apache Commons Net 库。这个库将提供一个NTPUDPClient类来管理无连接的 NTP 请求并返回一个TimeInfo实例。此实例应计算系统时间和 NTP 服务器时间之间的偏移量。让我们尝试在这里实现它:

  1. Apache Commons Net 库添加到您的项目中。
<dependency>
  <groupId>commons-net</groupId>
  <artifactId>commons-net</artifactId>
  <version>3.6</version>
</dependency>
  1. 创建NTPUDPClient该类的新实例。
  2. 设置默认超时和InetAddressNTP 服务器。
  3. 调用该NTPUDPClient.getTime()方法TimeInfo从指定服务器检索具有时间信息的实例。
  4. 调用computeDetails()方法来计算和验证 NTP 消息包的详细信息。
  5. 最后,得到offset并计算一个原子时间。

这里我们有一个基本的实现:

import java.net.InetAddress;
import java.util.Date;
import org.apache.commons.net.ntp.NTPUDPClient; 
import org.apache.commons.net.ntp.TimeInfo;

public class NTPClient {
  private static final String SERVER_NAME = "pool.ntp.org";

  private volatile TimeInfo timeInfo;
  private volatile Long offset;

  public static void main() throws Exception {

    NTPUDPClient client = new NTPUDPClient();
    // We want to timeout if a response takes longer than 10 seconds
    client.setDefaultTimeout(10_000);

    InetAddress inetAddress = InetAddress.getByName(SERVER_NAME);
    TimeInfo timeInfo = client.getTime(inetAddress);
    timeInfo.computeDetails();
    if (timeInfo.getOffset() != null) {
        this.timeInfo = timeInfo;
        this.offset = timeInfo.getOffset();
    }

    // This system NTP time
    TimeStamp systemNtpTime = TimeStamp.getCurrentTime();
    System.out.println("System time:\t" + systemNtpTime + "  " + systemNtpTime.toDateString());

    // Calculate the remote server NTP time
    long currentTime = System.currentTimeMillis();
    TimeStamp atomicNtpTime = TimeStamp.getNtpTime(currentTime + offset).getTime()

    System.out.println("Atomic time:\t" + atomicNtpTime + "  " + atomicNtpTime.toDateString());
  }

  public boolean isComputed()
  {
    return timeInfo != null && offset != null;
  }
}

你会得到类似的东西:

System time:    dfaa2c15.2083126e  Thu, Nov 29 2018 18:12:53.127
Atomic time:    dfaa2c15.210624dd  Thu, Nov 29 2018 18:12:53.129
于 2019-07-11T01:15:33.313 回答