Network Time Protocol (NTP) is a network protocol used for Packet Exchange to synchronize the clock of two computers. NTP uses UDP port 123 as the transport layer. It is used to offset the impact of variable latency.
NTP is one of the oldest network protocols in use (started before January 1, 1985 ). NTP was initially designed by Dave Mills at the University of Drava, and he and a group of volunteers are still maintaining NTP.
Common NTP server reference http://www.douban.com/note/171309770/
The NTP server using beiyou is the fastest, but it cannot be accessed on the Internet. It is recommended that the NTP service of Shanghai Jiao Tong University be accessible on other networks.
Two classes: one for parsing NTP messages, and the other for obtaining time based on the configuration file using the NTP protocol. Because it is a javaee project, the file path uses the path of servletactioncontext. For general Java projects, write the configuration path.
Package monitor. util; import Java. io. file; import Java. io. fileinputstream; import Java. io. filenotfoundexception; import Java. io. ioexception; import Java. io. interruptedioexception; import java.net. connectexception; import java.net. datagrampacket; import java.net. datagramsocket; import java.net. inetaddress; import java.net. noroutetohostexception; import java.net. unknownhostexception; import Java. text. decimalform At; import Java. text. simpledateformat; import Java. util. date; import Java. util. properties; import Org. apache. struts2.servletactioncontext; public class ntputil {static final string configfile = servletactioncontext. getservletcontext (). getrealpath (file. separator + "WEB-INF" + file. separator + "time.txt"); static string ntpserver = NULL; static integer retry = NULL; static integer Port = NULL; static integer Timeout = NULL;/*** reads the configuration in time.txt and returns the difference between the standard time and the local time, in seconds ** @ return */public static double localclockoffset () {If (ntpserver = NULL) {properties props = new properties (); try {props. load (New fileinputstream (new file (configfile);} catch (filenotfoundexception e) {// todo auto-generated catch blocke. printstacktrace ();} catch (ioexception e) {// todo auto-generated catch blocke. printstacktrace ();} n Tpserver = props. getproperty ("server"); retry = integer. parseint (props. getproperty ("retry"); Port = integer. parseint (props. getproperty ("Port"); timeout = integer. parseint (props. getproperty ("timeout");} // get the address and NTP address request // inetaddress limit 4addr = NULL; try {limit 4addr = inetaddress. getbyname (ntpserver); // For more information about NTP time server, refer to Note} catch (unknownhostexception E1) {e1.printstacktrace ();} int Servicestatus =-1; datagramsocket socket = NULL; long responsetime =-1; double localclockoffset = 0; try {socket = new datagramsocket (); socket. setsotimeout (timeout); // will force the // interruptedioexceptionfor (INT attempts = 0; Attempts <= retry & servicestatus! = 1; Attempts ++) {try {// send NTP request // byte [] DATA = new ntpmessage (). tobytearray (); datagrampacket outgoing = new datagrampacket (data, data. length, ipv4addr, Port); long senttime = system. currenttimemillis (); socket. send (outgoing); // get NTP response // byte [] buffer = new byte [512]; datagrampacket incoming = new datagrampacket (data, data. length); socket. receive (incoming); responsetime = system. curr Enttimemillis ()-senttime; double destinationtimestamp = (system. currenttimemillis ()/1000.0) + 2208988800.0; // Add 2208988800 here because the obtained time is Greenwich mean time, so the time is changed to GMT, otherwise there will be an 8-hour time difference with Beijing time // validate NTP response // ioexception thrown if packet does not decode as expected. ntpmessage MSG = new ntpmessage (incoming. getdata (); localclockoffset = (MSG. receivetimestamp-MSG. originatetimestamp) + (MSG. transmittimestam P-destinationtimestamp)/2; // system. out //. println ("poll: valid NTP request received ed the local clock offset is" // + localclockoffset // + ", responsetime =" // + responsetime + "Ms "); // system. out. println ("poll: NTP message:" + // MSG. tostring (); servicestatus = 1;} catch (interruptedioexception ex) {// ignore, no response received ed .}}} catch (noroutetohostexception e) {system. out. println ("No Route to host exception for address: "+ ipv4addr);} catch (connectexception e) {// connection refused. continue to retry. e. fillinstacktrace (); system. out. println ("connection exception for address:" + ipv4addr);} catch (ioexception ex) {ex. fillinstacktrace (); system. out. println ("ioexception while polling address:" + ipv4addr);} finally {If (socket! = NULL) socket. close () ;}// store response time if available /// if (servicestatus = 1) {// system. out. println ("responsetime =" + responsetime); //} return localclockoffset ;}} class ntpmessage {/*** // *** this is a two-bit code warning of an impending leap second to be * inserted/deleted in the last minute of the current day. it's values may * Be as follows: ** Value Meaning ----- ------- 0 no warning 1 last minute has 61 seconds 2 * last minute has 59 seconds) 3 alarm condition (clock not synchronized) */Public byte leapindicator = 0;/*** // *** this value indicates the NTP/SNTP version number. the version number is 3 * for Version 3 (IPv4 only) and 4 for version 4 (IPv4, IPv6 and OSI ). if * necessary to distinguish between IPv4, IPv6 and OSI, The encapsulating * context must be inspected. */Public byte version = 3;/*** // *** this value indicates the mode, with values defined as follows: ** mode meaning ---- ------- 0 reserved 1 reply Ric active 2 reply Ric * passive 3 client 4 Server 5 broadcast 6 reserved for NTP control message * 7 reserved for private use ** in unicast and anycast Modes, the client sets this field to 3 (client) in * the request and the server sets it to 4 (server) in the reply. in * multicast mode, the server sets this field to 5 (broadcast ). */Public byte mode = 0;/*** // *** this value indicates the stratum level of the local clock, with values * defined as follows: ** stratum meaning ------------------------------------------------ 0 * unspecified or unavailable 1 primary reference (e.g ., radio clock) 2-15 * Secondary reference (via NTP or SNTP) 16-255 reserved */Public short stratum = 0; /*** // *** this value indicates the maximum interval between successive messages, in * seconds to the nearest power of two. the values that can appear in this * field presently range from 4 (16 s) to 14 (16284 S); however, most * applications use only the sub-range 6 (64 s) to 10 (1024 S ). */Public byte pollinterval = 0;/*** // *** this value indicates the precision of the local clock, in seconds to the * nearest power of two. the values that normally appear in this field range * From-6 for mains-frequency clocks to-20 for microsecond clocks found in * Some workstations. */Public byte precision = 0;/*** // *** this value indicates the total roundtrip delay to the primary reference * source, in seconds. note that this variable can take on both positive and * negative values, depending on the relative Time and Frequency offsets. * The values that normally appear in this field range from negative values * Of a few milliseconds to positive values of several hundred milliseconds. */Public double rootdelay = 0;/*** // *** this value indicates the nominal error relative to the primary reference * source, in seconds. the values that normally appear in this field range * from 0 to several hundred milliseconds. */Public double rootdispersion = 0;/*** // *** this is a 4-byte array identifying the participates reference source. in * the case of NTP Version 3 or version 4 stratum-0 (Unspecified) or * stratum-1 (primary) servers, This is a four-character ASCII string, left * justified and zero padded to 32 bits. in NTP Version 3 secondary servers, * This is the 32-bit IPv4 address of the reference source. in NTP version 4 * Secondary servers, this is the low order 32 bits of the latest transmit * timestamp of the reference source. NTP primary (stratum 1) servers shoshould * set this field to a code identifying the external reference source * according to the following list. if the external reference is one of * those listed, the associated code shocould be used. codes for sources not * listed can be contrived as appropriate. ** code external reference source ---- ------------------------- locl * uncalibrated local clock used as a primary reference for a subnet without * external means of synchronization PPS atomic clock or other * pulse-per-second source individually calibrated to National Standards * acts NIST dialup modem service usno modem service PTB (Germany) * modem service TDF allouis (France) Radio 164 kHz DCF mainflingen * (Germany) Radio 77.5 kHz MSF rugby (UK) Radio 60 kHz WWV ft. collins (US) * radio 2.5, 5, 10, 15, 20 MHz wwvb Boulder (US) Radio 60 kHz wwh_kaui * Hawaii (US) Radio 2.5, 5, 10, 15 MHz Chu Ottawa (Canada) Radio 3330, * 7335,146 70 kHz lorc LORAN-C radionavigation system omeg Omega * radionavigation system GPS Global Positioning Service GOES Geostationary * orbit environment satellite */Public byte [] referenceidentifier = {0, 0, 0, 0};/*** // *** this is the time at which the local clock was last set or corrected, in * seconds since 1-Jan-1900. */Public double referencetimestamp = 0;/*** // *** this is the time at which the request departed the client for the server, * In seconds since 1-Jan-1900. */Public double originatetimestamp = 0;/*** // *** this is the time at which the request arrived at the server, in seconds * since 1-Jan-1900. */Public double receivetimestamp = 0;/*** // *** this is the time at which the reply departed the server for the client, * In seconds since 1-Jan-1900. */Public double transmittimestamp = 0;/*** // *** constructs a new ntpmessage from an array of bytes. */Public ntpmessage (byte [] array) {// see the packet format dimo-in RFC 2030 for detailsleapindicator = (byte) (array [0]> 6) & 0x3); version = (byte) (array [0]> 3) & 0x7); mode = (byte) (array [0] & 0x7); stratum = unsignedbytetoshort (array [1]); pollinterval = array [2]; precision = array [3]; rootdelay = (array [4] * 256.0) + unsignedbytetoshort (array [5]) + (unsignedbytetoshort (array [6])/256.0) + (unsignedbytetoshort (array [7]) /65536.0); rootdispersion = (unsignedbytetoshort (array [8]) * 256.0) + unsignedbytetoshort (array [9]) + (unsignedbytetoshort (array [10])/256.0) + (unsignedbytetoshort (array [11])/65536.0); referenceidentifier [0] = array [12]; referenceidentifier [1] = array [13]; referenceidentifier [2] = array [14]; referenceidentifier [3] = array [15]; referencetimestamp = decodetimestamp (array, 16); originatetimestamp = decodetimestamp (array, 24 ); vertex = decodetimestamp (array, 32); transmittimestamp = decodetimestamp (array, 40);}/*** // *** constructs a new ntpmessage */Public ntpmessage (byte leapindicator, byte version, byte mode, short stratum, byte pollinterval, byte precision, double rootdelay, double rootdispersion, byte [] referenceidentifier, double partial, double partial, double receivetimestamp, double transmittimestamp) {// todo: Validity checkingthis. leapindicator = leapindicator; this. version = version; this. mode = mode; this. stratum = stratum; this. pollinterval = pollinterval; this. precision = precision; this. rootdelay = rootdelay; this. rootdispersion = rootdispersion; this. referenceidentifier = referenceidentifier; this. referencetimestamp = referencetimestamp; this. originatetimestamp = originatetimestamp; this. receivetimestamp = receivetimestamp; this. transmittimestamp = transmittimestamp;}/*** // *** constructs a new ntpmessage in client-> server mode, and sets the * transmit timestamp to the current time. */Public ntpmessage () {// note that all the other member variables are already set with // appropriate default values. this. mode = 3; this. transmittimestamp = (system. currenttimemillis ()/1000.0) + 2208988800.0;}/*** // *** this method constructs the data bytes of a raw NTP packet. */Public byte [] tobytearray () {// All bytes are automatically set to 0 byte [] P = new byte [48]; P [0] = (byte) (leapindicator <6 | version <3 | mode); P [1] = (byte) stratum; P [2] = (byte) pollinterval; P [3] = (byte) precision; // root delay is a signed 16.16-bit FP, in Java an int is 32-bitsint L = (INT) (rootdelay * 65536.0 ); P [4] = (byte) (L> 24) & 0xff); P [5] = (byte) (L> 16) & 0xff ); P [6] = (byte) (L> 8) & 0xff); P [7] = (byte) (L & 0xff ); // root dispersion is an unsigned 16.16-bit FP, in Java there are no // unsigned primitive types, so we use a long which is 64-bitslong ul = (long) (rootdispersion * 65536.0); P [8] = (byte) (UL> 24) & 0xff); P [9] = (byte) (UL> 16) & 0xff); P [10] = (byte) (UL> 8) & 0xff); P [11] = (byte) (UL & 0xff ); P [12] = referenceidentifier [0]; P [13] = referenceidentifier [1]; P [14] = referenceidentifier [2]; P [15] = referenceidentifier [3]; encodetimestamp (p, 16, latency); encodetimestamp (p, 24, latency); encodetimestamp (p, 32, receivetimestamp); encodetimestamp (p, 40, transmittimestamp); Return P ;} /*** // *** returns a string representation of a ntpmessage */Public String tostring () {string precisionstr = new decimalformat ("0. # E0 "). format (math. pow (2, precision); Return "Leap indicator:" + leapindicator + "" + "version:" + version + "" + "Mode: "+ mode +" "+" stratum: "+ stratum +" "+" poll: "+ pollinterval +" "+" precision: "+ precision +" ("+ precisionstr +" seconds) "+" root delay: "+ new decimalformat (" 0.00 "). format (rootdelay * 1000) + "MS" + "root Dispersion:" + new decimalformat ("0.00 "). format (rootdispersion * 1000) + "MS" + "reference identifier:" + identifier (referenceidentifier, stratum, Version) + "" + "reference timestamp:" + timestamptostring (referencetimestamp) + "" + "originate timestamp:" + timestamptostring (originatetimestamp) + "" + "receive timestamp:" + timestamptostring (receivetimestamp) + "" + "transmit timestamp: "+ timestamptostring (transmittimestamp);}/*** // *** converts an unsigned byte to a short. by default, Java assumes that a * byte is signed. */public static short unsignedbytetoshort (byte B) {If (B & 0x80) = 0x80) Return (short) (128 + (B & 0x7f )); elsereturn (short) B ;} /*** // *** will read 8 bytes of a message beginning at <code> pointer </code> and * return it as a double, according to the NTP 64-bit timestamp format. */public static double decodetimestamp (byte [] array, int pointer) {double r = 0.0; For (INT I = 0; I <8; I ++) {R + = unsignedbytetoshort (array [pointer + I]) * Math. pow (2, (3-I) * 8);} return r ;} /*** // *** encodes a timestamp in the specified position in the message */public static void encodetimestamp (byte [] array, int pointer, double timestamp) {// converts a double into a 64-Bit fixed pointfor (INT I = 0; I <8; I ++) {// 2 ^ 24, 2 ^ 16, 2 ^ 8 ,.. 2 ^-32 double base = math. pow (2, (3-I) * 8); // capture byte valuearray [pointer + I] = (byte) (timestamp/base ); // subtract captured value from remaining totaltimestamp = timestamp-(double) (unsignedbytetoshort (array [pointer + I]) * base);} // From RFC 2030: it is advisable to fill the non-significant // low order bits of the timestamp with a random, unbiased // bitstring, both to avoid systematic roundoff errors and as // a means of loop detection and replay detection. array [7] = (byte) (math. random () * 255.0);}/*** // *** returns a timestamp (number of seconds since 1-Jan-1900) as a * formatted date/time string. */public static string timestamptostring (double timestamp) {If (timestamp = 0) Return "0"; // timestamp is relative to 1900, UTC is used by Java and is relative // to 1970 double UTC = timestamp-(2208988800.0); // millisecondslong MS = (long) (UTC * 1000.0 ); // Date/timestring date = new simpledateformat ("DD-mmm-yyyy hh: mm: SS "). format (new date (MS); // fractiondouble fraction = timestamp-(long) timestamp); string fractionsting = new decimalformat (". 000000 "). format (fraction); return date + fractionsting;}/*** // *** returns a string representation of a reference identifier according to * the rules set out in RFC 2030. */public static string referenceidentifiertostring (byte [] ref, short stratum, byte version) {// from the RFC 2030: // In the case of NTP Version 3 or version 4 stratum-0 (Unspecified) // or stratum-1 (primary) servers, This is a four-character ASCII // string, left justified and zero padded to 32 bits. if (stratum = 0 | stratum = 1) {return new string (REF);} // in NTP Version 3 secondary servers, this is the 32-bit IPv4 // address of the reference source. else if (version = 3) {return unsignedbytetoshort (Ref [0]) + ". "+ unsignedbytetoshort (Ref [1]) + ". "+ unsignedbytetoshort (Ref [2]) + ". "+ unsignedbytetoshort (Ref [3]);} // in NTP version 4 secondary servers, this is the low order 32 bits // of the latest transmit timestamp of the reference source. else if (version = 4) {return "" + (unsignedbytetoshort (Ref [0])/256.0) + (unsignedbytetoshort (Ref [1])/65536.0) + (unsignedbytetoshort (Ref [2])/16777216.0) + (unsignedbytetoshort (Ref [3])/4294967296.0);} return "";}}
The configuration file is simple:
Server = ntp.sjtu.edu.cn
Retry = 2
Port = 123
Timeout = 3000