NTP授时原理:
客户端使用上述四个时间戳参数(T1、T2、T3、T4)来计算两个关键参数:
NTP报文从客户端到服务器的往返延迟(Delay):Delay = (T4 - T1) - (T3 - T2)
客户端与服务端之间的时间差(Offset):Offset = ((T2 - T1) + (T3 - T4)) / 2
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.8.0</version> <!-- 请检查最新版本 -->
</dependency>
import org.apache.commons.net.ntp.NTPUDPClient;
import org.apache.commons.net.ntp.TimeInfo;
import org.apache.commons.net.ntp.TimeStamp;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.Date;
public class NTPClient {
public static void main(String[] args) throws InterruptedException {
for(int i = 0;i<10;i++){
Thread.sleep(1000);
try {
NTPUDPClient timeClient = new NTPUDPClient();
//String ntpServer = "130.149.17.21";
String ntpServer = "pool.ntp.org";
InetAddress inetAddress = InetAddress.getByName(ntpServer);
timeClient.open();
timeClient.setVersion(3);
timeClient.setDefaultTimeout(3000); // 设置超时时间(毫秒)
TimeInfo timeInfo = timeClient.getTime(inetAddress);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
//取时间
TimeStamp OriginateTimeStamp = timeInfo.getMessage().getOriginateTimeStamp();//报文到达服务器的时间戳 t0 (图中T1)
TimeStamp ReceiveTimeStamp = timeInfo.getMessage().getReceiveTimeStamp();//服务器发送应答报文的时间戳 t1(图中T2)
TimeStamp TransmitTimeStamp = timeInfo.getMessage().getTransmitTimeStamp();//报文离开客户端的时间戳 t2(图中T3)
long t0 = OriginateTimeStamp.getTime();
long t1 = ReceiveTimeStamp.getTime();
long t2 = TransmitTimeStamp.getTime();
long ntpTime0 = OriginateTimeStamp.getTime();
Date ntpDate0 = new Date(ntpTime0);
String formattedDate0 = dateFormat.format(ntpDate0);
System.out.println("t0: " + formattedDate0);
long ntpTime1 = ReceiveTimeStamp.getTime();
Date ntpDate1 = new Date(ntpTime1);
String formattedDate1 = dateFormat.format(ntpDate1);
System.out.println("t1: " + formattedDate1);
long ntpTime2 = TransmitTimeStamp.getTime();
Date ntpDate2 = new Date(ntpTime2);
String formattedDate2 = dateFormat.format(ntpDate2);
System.out.println("t2: " + formattedDate2);
//long ntpTime3 = OriginateTimeStamp.getTime(); // OriginateTimeStamp是服务器端获得授时的最新时刻
//Date ntpDate3 = new Date(ntpTime3);
long t3 = System.currentTimeMillis();
String formattedDate3 = dateFormat.format(t3);
System.out.println("t3: " + formattedDate3);
System.out.println("delay:" +(t1-t0+t3-t2)/2);
System.out.println("Offset:" +(t1-t0+t2-t3)/2); // 计算的Offset
long now = (t2+((t1-t0+t2-t3)/2)); // now的时间戳取 当前(时间 + Offset)
System.out.println("now: " +now);
long now2 = t3; //本机系统时间
System.out.println("now2:"+now2);
System.out.println("本机系统时间与计算得到的授时时间Offset"+(now2 - now));
timeClient.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
参考资料: