Java NTP UDP 客户端



import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.Date;

public class Client {

	public static long synchronize(String server) throws IOException {
		DatagramSocket socket = new DatagramSocket();
		socket.setSoTimeout(2000);

		// Build NTP Packet
		Packet ntpPacket = new Packet();
		long t0 = System.currentTimeMillis();
		ntpPacket.setTransmitTimestamp(new Packet.Timestamp(t0));

		// Convert packet to datagram packet
		byte[] ntpRawPacket = ntpPacket.asByteArray();
		DatagramPacket packet = new DatagramPacket(ntpRawPacket,
				ntpRawPacket.length, InetAddress.getByName(server), 123);

		// Send and wait for response
		socket.send(packet);
		socket.receive(packet);

		// Extract timestamps from packet
		long t3 = System.currentTimeMillis();
		Packet recvPacket = new Packet(ByteBuffer.wrap(packet.getData()));
		long t1 = recvPacket.getReceiveTimestamp().getTimeMillis();
		long t2 = recvPacket.getTransmitTimestamp().getTimeMillis();

		socket.close();

		return (t1 + t2 - t0 - t3 + 1) / 2;
	}

	public static void main(String[] args) throws IOException {
		long diff = synchronize("ntp1.aliyun.com");
		System.out.println(new Date(System.currentTimeMillis() + diff));
	}

}


import java.nio.ByteBuffer;

public class Packet {

	public static class Timestamp {
		private final long seconds;
		private final long fraction;

		public Timestamp(long time) {
			seconds = time / 1000 + 2208988800L;
			long milli = time % 1000;
			fraction = (milli * 0x100000000L + 500) / 1000;
		}

		public Timestamp(long seconds, long fraction) {
			if (Integer.toUnsignedLong((int) seconds) != seconds)
				throw new IllegalArgumentException(
						"Seconds outside valid range");
			if (Integer.toUnsignedLong((int) fraction) != fraction)
				throw new IllegalArgumentException(
						"Fraction outside valid range");
			this.seconds = seconds;
			this.fraction = fraction;
		}

		public long getSeconds() {
			return seconds;
		}

		public long getFraction() {
			return fraction;
		}

		public long getTimeMillis() {
			long time = (seconds - 2208988800L) * 1000;
			long milli = (fraction * 1000 + 0x80000000L) / 0x100000000L;
			return time + milli;
		}

	}

	ByteBuffer buffer;

	public Packet() {
		buffer = ByteBuffer.allocate(48);

		setLeapIndicator(3);
		setVersion(4);
		setMode(3);
	}

	public Packet(ByteBuffer buffer) {
		if (buffer.limit() < 48)
			throw new IllegalArgumentException("Buffer size is less than 48");
		this.buffer = buffer;
	}

	public void setLeapIndicator(int leapIndicator) {
		if (leapIndicator < 0 || leapIndicator >= 4)
			throw new IllegalArgumentException(
					"Leap Indicator outside valid range");
		byte b = buffer.get(0);
		b &= ~0b11000000;
		b |= leapIndicator << 6;
		buffer.put(0, b);
	}

	public void setVersion(int version) {
		if (version < 0 || version >= 8)
			throw new IllegalArgumentException("Version outside valid range");
		byte b = buffer.get(0);
		b &= ~0b00111000;
		b |= version << 3;
		buffer.put(0, b);
	}

	public void setMode(int mode) {
		if (mode < 0 || mode >= 8)
			throw new IllegalArgumentException("Mode outside valid range");
		byte b = buffer.get(0);
		b &= ~0b0000111;
		b |= mode;
		buffer.put(0, b);
	}

	public void setTransmitTimestamp(Timestamp t) {
		buffer.putInt(40, (int) t.getSeconds());
		buffer.putInt(44, (int) t.getFraction());
	}

	public Timestamp getReceiveTimestamp() {
		long seconds = Integer.toUnsignedLong(buffer.getInt(32));
		long fraction = Integer.toUnsignedLong(buffer.getInt(36));
		return new Timestamp(seconds, fraction);
	}
	
	public Timestamp getTransmitTimestamp() {
		long seconds = Integer.toUnsignedLong(buffer.getInt(40));
		long fraction = Integer.toUnsignedLong(buffer.getInt(44));
		return new Timestamp(seconds, fraction);
	}

	public byte[] asByteArray() {
		return buffer.array();
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值