您的位置:首页 > 移动开发 > Android开发

Android 通过NTP服务器自动获取时间的方法

2014-02-20 09:33 218 查看
importjava.net.DatagramPacket;

importjava.net.DatagramSocket;

importjava.net.InetAddress;

importjava.util.Date;

publicclassGetTime {

publicstaticvoidmain(String[] args) {

SntpClient client = newSntpClient();

if(client.requestTime("pool.ntp.org", 30000)) {

longnow = client.getNtpTime() + System.nanoTime() / 1000

- client.getNtpTimeReference();

Date current = newDate(now);

System.out.println(current.toString());

}

}

}

classSntpClient {

privatestaticfinalintORIGINATE_TIME_OFFSET = 24;

privatestaticfinalintRECEIVE_TIME_OFFSET = 32;

privatestaticfinalintTRANSMIT_TIME_OFFSET = 40;

privatestaticfinalintNTP_PACKET_SIZE = 48;

privatestaticfinalintNTP_PORT = 123;

privatestaticfinalintNTP_MODE_CLIENT = 3;

privatestaticfinalintNTP_VERSION = 3;

// Number of seconds between Jan 1, 1900 and Jan 1, 1970 // 70 years plus 17 leap days privatestaticfinallongOFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;

// system time computed from NTP server response privatelongmNtpTime;

// value of SystemClock.elapsedRealtime() corresponding to mNtpTime privatelongmNtpTimeReference;

// round trip time in milliseconds privatelongmRoundTripTime;

/**

* Sends an SNTP request to the given host and processes the response.

*

* @param host

* host name of the server.

* @param timeout

* network timeout in milliseconds.

* @return true if the transaction was successful.

*/

publicbooleanrequestTime(String host, inttimeout) {

try{

DatagramSocket socket = newDatagramSocket();

socket.setSoTimeout(timeout);

InetAddress address = InetAddress.getByName(host);

byte[] buffer = newbyte[NTP_PACKET_SIZE];

DatagramPacket request = newDatagramPacket(buffer, buffer.length,

address, NTP_PORT);

// set mode = 3 (client) and version = 3 // mode is in low 3 bits of first byte // version is in bits 3-5 of first byte buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);

// get current time and write it to the request packet longrequestTime = System.currentTimeMillis();

longrequestTicks = System.nanoTime() / 1000;

writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime);

socket.send(request);

// read the response DatagramPacket response = newDatagramPacket(buffer, buffer.length);

socket.receive(response);

longresponseTicks = System.nanoTime() / 1000;

longresponseTime = requestTime + (responseTicks - requestTicks);

socket.close();

// extract the results longoriginateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET);

longreceiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);

longtransmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET);

longroundTripTime = responseTicks - requestTicks

- (transmitTime - receiveTime);

// receiveTime = originateTime + transit + skew // responseTime = transmitTime + transit - skew // clockOffset = ((receiveTime - originateTime) + (transmitTime - // responseTime))/2 // = ((originateTime + transit + skew - originateTime) + // (transmitTime -
(transmitTime + transit - skew)))/2 // = ((transit + skew) + (transmitTime - transmitTime - transit + // skew))/2 // = (transit + skew - transit + skew)/2 // = (2 * skew)/2 = skew longclockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))
/ 2;

// if (Config.LOGD) Log.d(TAG, "round trip: " + roundTripTime + // " ms"); // if (Config.LOGD) Log.d(TAG, "clock offset: " + clockOffset + // " ms"); // save our results - use the times on this side of the network // latency // (response rather than request
time) mNtpTime = responseTime + clockOffset;

mNtpTimeReference = responseTicks;

mRoundTripTime = roundTripTime;

} catch(Exception e) {

returnfalse;

}

returntrue;

}

/**

* Returns the time computed from the NTP transaction.

*

* @return time value computed from NTP server response.

*/

publiclonggetNtpTime() {

returnmNtpTime;

}

/**

* Returns the reference clock value (value of

* SystemClock.elapsedRealtime()) corresponding to the NTP time.

*

* @return reference clock corresponding to the NTP time.

*/

publiclonggetNtpTimeReference() {

returnmNtpTimeReference;

}

/**

* Returns the round trip time of the NTP transaction

*

* @return round trip time in milliseconds.

*/

publiclonggetRoundTripTime() {

returnmRoundTripTime;

}

/**

* Reads an unsigned 32 bit big endian number from the given offset in the

* buffer.

*/

privatelongread32(byte[] buffer, intoffset) {

byteb0 = buffer[offset];

byteb1 = buffer[offset + 1];

byteb2 = buffer[offset + 2];

byteb3 = buffer[offset + 3];

// convert signed bytes to unsigned values inti0 = ((b0 & 0x80) == 0x80? (b0 & 0x7F) + 0x80: b0);

inti1 = ((b1 & 0x80) == 0x80? (b1 & 0x7F) + 0x80: b1);

inti2 = ((b2 & 0x80) == 0x80? (b2 & 0x7F) + 0x80: b2);

inti3 = ((b3 & 0x80) == 0x80? (b3 & 0x7F) + 0x80: b3);

return((long) i0 << 24) + ((long) i1 << 16) + ((long) i2 << + (long) i3;

}

/**

* Reads the NTP time stamp at the given offset in the buffer and returns it

* as a system time (milliseconds since January 1, 1970).

*/

privatelongreadTimeStamp(byte[] buffer, intoffset) {

longseconds = read32(buffer, offset);

longfraction = read32(buffer, offset + 4);

return((seconds - OFFSET_1900_TO_1970) * 1000)

+ ((fraction * 1000L) / 0x100000000L);

}

/**

* Writes system time (milliseconds since January 1, 1970) as an NTP time

* stamp at the given offset in the buffer.

*/

privatevoidwriteTimeStamp(byte[] buffer, intoffset, longtime) {

longseconds = time / 1000L;

longmilliseconds = time - seconds * 1000L;

seconds += OFFSET_1900_TO_1970;

// write seconds in big endian format buffer[offset++] = (byte) (seconds >> 24);

buffer[offset++] = (byte) (seconds >> 16);

buffer[offset++] = (byte) (seconds >> 8);

buffer[offset++] = (byte) (seconds >> 0);

longfraction = milliseconds * 0x100000000L / 1000L;

// write fraction in big endian format buffer[offset++] = (byte) (fraction >> 24);

buffer[offset++] = (byte) (fraction >> 16);

buffer[offset++] = (byte) (fraction >> 8);

// low order bits should be random data buffer[offset++] = (byte) (Math.random() * 255.0);

}

}

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.InetAddress;

import java.util.Date;

public class GetTime {

public static void main(String[] args) {

SntpClient client = new SntpClient();

if (client.requestTime("pool.ntp.org", 30000)) {

long now = client.getNtpTime() + System.nanoTime() / 1000

- client.getNtpTimeReference();

Date current = new Date(now);

System.out.println(current.toString());

}

}

}

class SntpClient {

private static final int ORIGINATE_TIME_OFFSET = 24;

private static final int RECEIVE_TIME_OFFSET = 32;

private static final int TRANSMIT_TIME_OFFSET = 40;

private static final int NTP_PACKET_SIZE = 48;

private static final int NTP_PORT = 123;

private static final int NTP_MODE_CLIENT = 3;

private static final int NTP_VERSION = 3;

// Number of seconds between Jan 1, 1900 and Jan 1, 1970

// 70 years plus 17 leap days

private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;

// system time computed from NTP server response

private long mNtpTime;

// value of SystemClock.elapsedRealtime() corresponding to mNtpTime

private long mNtpTimeReference;

// round trip time in milliseconds

private long mRoundTripTime;

/**

* Sends an SNTP request to the given host and processes the response.

*

* @param host

* host name of the server.

* @param timeout

* network timeout in milliseconds.

* @return true if the transaction was successful.

*/

public boolean requestTime(String host, int timeout) {

try {

DatagramSocket socket = new DatagramSocket();

socket.setSoTimeout(timeout);

InetAddress address = InetAddress.getByName(host);

byte[] buffer = new byte[NTP_PACKET_SIZE];

DatagramPacket request = new DatagramPacket(buffer, buffer.length,

address, NTP_PORT);

// set mode = 3 (client) and version = 3

// mode is in low 3 bits of first byte

// version is in bits 3-5 of first byte

buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);

// get current time and write it to the request packet

long requestTime = System.currentTimeMillis();

long requestTicks = System.nanoTime() / 1000;

writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime);

socket.send(request);

// read the response

DatagramPacket response = new DatagramPacket(buffer, buffer.length);

socket.receive(response);

long responseTicks = System.nanoTime() / 1000;

long responseTime = requestTime + (responseTicks - requestTicks);

socket.close();

// extract the results

long originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET);

long receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);

long transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET);

long roundTripTime = responseTicks - requestTicks

- (transmitTime - receiveTime);

// receiveTime = originateTime + transit + skew

// responseTime = transmitTime + transit - skew

// clockOffset = ((receiveTime - originateTime) + (transmitTime -

// responseTime))/2

// = ((originateTime + transit + skew - originateTime) +

// (transmitTime - (transmitTime + transit - skew)))/2

// = ((transit + skew) + (transmitTime - transmitTime - transit +

// skew))/2

// = (transit + skew - transit + skew)/2

// = (2 * skew)/2 = skew

long clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime)) / 2;

// if (Config.LOGD) Log.d(TAG, "round trip: " + roundTripTime +

// " ms");

// if (Config.LOGD) Log.d(TAG, "clock offset: " + clockOffset +

// " ms");

// save our results - use the times on this side of the network

// latency

// (response rather than request time)

mNtpTime = responseTime + clockOffset;

mNtpTimeReference = responseTicks;

mRoundTripTime = roundTripTime;

} catch (Exception e) {

return false;

}

return true;

}

/**

* Returns the time computed from the NTP transaction.

*

* @return time value computed from NTP server response.

*/

public long getNtpTime() {

return mNtpTime;

}

/**

* Returns the reference clock value (value of

* SystemClock.elapsedRealtime()) corresponding to the NTP time.

*

* @return reference clock corresponding to the NTP time.

*/

public long getNtpTimeReference() {

return mNtpTimeReference;

}

/**

* Returns the round trip time of the NTP transaction

*

* @return round trip time in milliseconds.

*/

public long getRoundTripTime() {

return mRoundTripTime;

}

/**

* Reads an unsigned 32 bit big endian number from the given offset in the

* buffer.

*/

private long read32(byte[] buffer, int offset) {

byte b0 = buffer[offset];

byte b1 = buffer[offset + 1];

byte b2 = buffer[offset + 2];

byte b3 = buffer[offset + 3];

// convert signed bytes to unsigned values

int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);

int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);

int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);

int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);

return ((long) i0 << 24) + ((long) i1 << 16) + ((long) i2 <<

+ (long) i3;

}

/**

* Reads the NTP time stamp at the given offset in the buffer and returns it

* as a system time (milliseconds since January 1, 1970).

*/

private long readTimeStamp(byte[] buffer, int offset) {

long seconds = read32(buffer, offset);

long fraction = read32(buffer, offset + 4);

return ((seconds - OFFSET_1900_TO_1970) * 1000)

+ ((fraction * 1000L) / 0x100000000L);

}

/**

* Writes system time (milliseconds since January 1, 1970) as an NTP time

* stamp at the given offset in the buffer.

*/

private void writeTimeStamp(byte[] buffer, int offset, long time) {

long seconds = time / 1000L;

long milliseconds = time - seconds * 1000L;

seconds += OFFSET_1900_TO_1970;

// write seconds in big endian format

buffer[offset++] = (byte) (seconds >> 24);

buffer[offset++] = (byte) (seconds >> 16);

buffer[offset++] = (byte) (seconds >> 8);

buffer[offset++] = (byte) (seconds >> 0);

long fraction = milliseconds * 0x100000000L / 1000L;

// write fraction in big endian format

buffer[offset++] = (byte) (fraction >> 24);

buffer[offset++] = (byte) (fraction >> 16);

buffer[offset++] = (byte) (fraction >> 8);

// low order bits should be random data

buffer[offset++] = (byte) (Math.random() * 255.0);

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: