android ntp和GPS获取网络时间问题

来源:互联网 发布:山西大学教务网络 编辑:程序博客网 时间:2024/04/30 09:12

由于最近做的一个项目要用到ntp网络时间问题,特意去研究了一下ntp协议的问题,这里给出ntp协议的贴图和字段


主要字段的解释如下:

l              LI(Leap Indicator):长度为2比特,值为“11”时表示告警状态,时钟未被同步。为其他值时NTP本身不做处理。

l              VN(Version Number):长度为3比特,表示NTP的版本号,目前的最新版本为3。

l              Mode:长度为3比特,表示NTP的工作模式。不同的值所表示的含义分别是:0未定义、1表示主动对等体模式、2表示被动对等体模式、3表示客户模式、4表示服务器模式、5表示广播模式或组播模式、6表示此报文为NTP控制报文、7预留给内部使用。

l              Stratum:系统时钟的层数,取值范围为1~16,它定义了时钟的准确度。层数为1的时钟准确度最高,准确度从1到16依次递减,层数为16的时钟处于未同步状态,不能作为参考时钟。

l              Poll:轮询时间,即两个连续NTP报文之间的时间间隔。

l              Precision:系统时钟的精度。

l              Root Delay:本地到主参考时钟源的往返时间。

l              Root Dispersion:系统时钟相对于主参考时钟的最大误差。

l              Reference Identifier:参考时钟源的标识。

l              Reference Timestamp:系统时钟最后一次被设定或更新的时间。

l              Originate Timestamp:NTP请求报文离开发送端时发送端的本地时间。

l              Receive Timestamp:NTP请求报文到达接收端时接收端的本地时间。

l              Transmit Timestamp:应答报文离开应答者时应答者的本地时间。

l              Authenticator:验证信息。

当时我也在网上找了一些方法来在android设备上获取获取时间,但是都有一点小问题,这里我给出自己修改过后的代码。

public 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 daysprivate static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;// system time computed from NTP server responseprivate long mNtpTime;// value of SystemClock.elapsedRealtime() corresponding to mNtpTimeprivate long mNtpTimeReference;// round trip time in millisecondsprivate 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 bytebuffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);// get current time and write it to the request packetlong requestTime = System.currentTimeMillis();long requestTicks = SystemClock.elapsedRealtime();writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime);socket.send(request);// read the responseDatagramPacket response = new DatagramPacket(buffer, buffer.length);socket.receive(response);long responseTicks = SystemClock.elapsedRealtime();long responseTime = requestTime + (responseTicks - requestTicks);socket.close();// extract the resultslong 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 = skewlong 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 << 8)  + (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 formatbuffer[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 formatbuffer[offset++] = (byte) (fraction >> 24);buffer[offset++] = (byte) (fraction >> 16);buffer[offset++] = (byte) (fraction >> 8);// low order bits should be random databuffer[offset++] = (byte) (Math.random() * 255.0);}}

然后在使用的时候只需要这样就可以了

long now = client.getNtpTime()+ SystemClock.elapsedRealtime()- client.getNtpTimeReference();Date current = new Date(now);


但是这个时候只是有了ntp的时间信息,我还需要ntp的服务器信息。

这个时候我发现自己解析变得不怎么好使了,这个时候我又从网络上找到了NTPUDPClient,这个类,这个是apache提供的,主要能获取ntp的服务信息

然后我又自己封装了一下

public class SntpClientInfo {private NTPUDPClient ntpudpClient;private long time;//当前时间private String delay;//延时private String offset;//偏差private String mode;//模式private String originatetime;//请求时间private String recievetime;//到达时间private String transmittime;//响应时间private String referencetime;//返回时间private String stratum;//协议类型private int leap;//同步状态private int version;//版本号private int precision;//精确度private int poll;//轮换时间private float rootdelay;//总延时private float rootdisperion;//最大误差private String ip;//ip地址public long getTime() {return time;}public String getDelay() {return delay;}public String getOffset() {return offset;}public String getMode() {return mode;}public String getOriginatetime() {return originatetime;}public String getRecievetime() {return recievetime;}public String getTransmittime() {return transmittime;}public String getReferencetime() {return referencetime;}public String getStratum() {return stratum;}public int getLeap() {return leap;}public int getVersion() {return version;}public int getPrecision() {return precision;}public int getPoll() {return poll;}public float getRootdelay() {return rootdelay;}public float getRootdisperion() {return rootdisperion;}public String getIp() {return ip;}public SntpClientInfo() {ntpudpClient = new NTPUDPClient();}public boolean requestTime(String serve, int timeout) {boolean result = true;try {InetAddress host = InetAddress.getByName(serve);long requsttime = System.currentTimeMillis();ntpudpClient.open();ntpudpClient.setSoTimeout(timeout);TimeInfo info = ntpudpClient.getTime(host);delay = (System.currentTimeMillis() - requsttime) + "ms";time = info.getMessage().getTransmitTimeStamp().getDate().getTime();          //time = info.getReturnTime();//返回时间//delay = info.getDelay();//延时时间offset = (time - info.getReturnTime()) + "ms";//时差//offset = info.getOffset();//时差NtpV3Packet ntpV3Packet = info.getMessage();mode = ntpV3Packet.getModeName();//模式originatetime = ntpV3Packet.getOriginateTimeStamp().toDateString().substring(16);//请求时间recievetime = ntpV3Packet.getReceiveTimeStamp().toDateString().substring(16);//到达时间transmittime = ntpV3Packet.getTransmitTimeStamp().toDateString().substring(16);//响应时刻referencetime = ntpV3Packet.getReferenceTimeStamp().toDateString().substring(16);//返回时刻stratum = ntpV3Packet.getStratum() + ntpV3Packet.getType();//协议类型leap = ntpV3Packet.getLeapIndicator();//同步状态version = ntpV3Packet.getVersion();//b版本号mode = ntpV3Packet.getModeName() + "(" + ntpV3Packet.getMode() + ")";//模式precision = ntpV3Packet.getPrecision();//精确度poll = ntpV3Packet.getPoll();//轮换时间rootdelay = ntpV3Packet.getRootDelay() / 1000.0f;//总延时rootdisperion = ntpV3Packet.getRootDispersion() / 1000.0f;//最大误差ip = ntpV3Packet.getReferenceIdString();////ip地址System.out.println(ntpV3Packet.getReferenceIdString());} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();result = false;}return result;}}
这里就可以获取到NTP服务器信息了

然后就是GPS获取网络时间问题,

GPS获取网络时间很简单,几句代码就可以了。

LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, minTime, minDistance, listener)

然后在你的lisenler里面获取到location位置直接获取时间就可以了

原创粉丝点击