Search code examples
javaeclipsepacketdatagramtimestamping

DatagramPacket getData() not working


I'm attempting to grab a timestamp off an nist.gov server using the code below.

InetAddress addr = InetAddress.getByName("129.6.15.30");
DatagramSocket s = new DatagramSocket();
System.out.println("Connected to: "+addr.getHostName());

byte[] buf = new byte[4];
DatagramPacket p = new DatagramPacket(buf, buf.length, addr, 37);
s.send(p);
System.out.println("message sent");

DatagramPacket dp = new DatagramPacket(buf, buf.length);
s.receive(dp);
String data = new String(dp.getData(), 0, dp.getLength());
System.out.println("Received: "+data);

When I run this on Eclipse, I get the following back in the console.

Connected to: time-c.nist.gov
message sent
Received: ÛÏÌ<

Good news is, I'm connecting to the correct server and getting back a packet. However, I just can't seem to turn that packet's data into a comprehensible representation of that data. What am I missing?


Solution

  • The response from the Time Protocol is a 32 bit integer in network byte order - this is not a string.

    To read it you need to use something like DataInputStream:

    DataInputStream dis = new DataInputStream(new ByteArrayInputStream(dp.getData(), 0, dp.getLength()));
    
    int time = dis.readInt();
    
    dis.close();
    

    The time value returned is the number of seconds since 1st Jan 1900, to get a Java Instant from this we need to convert the unsigned integer to the standard Java 'epoch' which is the number of seconds since 1st Jan 1970:

    long secondsSince1Jan1900 = Integer.toUnsignedLong(time);
    
    long differenceBetweenEpochs = 2208988800L;
    
    long secondsSince1Jan1970 = secondsSince1Jan1900 - differenceBetweenEpochs;
    
    Instant instant = Instant.ofEpochSecond(secondsSince1Jan1970);