FileDocCategorySizeDatePackage
TimeClient.javaAPI DocExample5683Sun Apr 28 15:07:42 BST 2002com.ronsoft.books.nio.channels

TimeClient

public class TimeClient extends Object
Request time service, per RFC 868. RFC 868 (http://www.ietf.org/rfc/rfc0868.txt) is a very simple time protocol whereby one system can request the current time from another system. Most Linux, BSD and Solaris systems provide RFC 868 time service on port 37. This simple program will inter-operate with those. The National Institute of Standards and Technology (NIST) operates a public time server at time.nist.gov. The RFC 868 protocol specifies a 32 bit unsigned value be sent, representing the number of seconds since Jan 1, 1900. The Java epoch begins on Jan 1, 1970 (same as unix) so an adjustment is made by adding or subtracting 2,208,988,800 as appropriate. To avoid shifting and masking, a four-byte slice of an eight-byte buffer is used to send/recieve. But getLong() is done on the full eight bytes to get a long value. When run, this program will issue time requests to each hostname given on the command line, then enter a loop to receive packets. Note that some requests or replies may be lost, which means this code could block forever. Created: April 2002
author
Ron Hitchens (ron@ronsoft.com)
version
$Id: TimeClient.java,v 1.2 2002/04/28 22:07:43 ron Exp $

Fields Summary
private static final int
DEFAULT_TIME_PORT
private static final long
DIFF_1900
protected int
port
protected List
remoteHosts
protected DatagramChannel
channel
Constructors Summary
public TimeClient(String[] argv)


	      
	
		if (argv.length == 0) {
			throw new Exception ("Usage: [ -p port ] host ...");
		}

		parseArgs (argv);

		this.channel = DatagramChannel.open();
	
Methods Summary
public voidgetReplies()

		// allocate a buffer to hold a long value
		ByteBuffer longBuffer = ByteBuffer.allocate (8);

		// assure big-endian (network) byte order
		longBuffer.order (ByteOrder.BIG_ENDIAN);
		// zero the whole buffer to be sure
		longBuffer.putLong (0, 0);
		// position to first byte of the low-order 32 bits
		longBuffer.position (4);

		// slice the buffer, gives view of the low-order 32 bits
		ByteBuffer buffer = longBuffer.slice();	
		int expect = remoteHosts.size();
		int replies = 0;

		System.out.println ("");
		System.out.println ("Waiting for replies...");

		while (true) {
			InetSocketAddress sa;

			sa = receivePacket (channel, buffer);

			if (sa == null) {
				// only get here if receivePacket timed out
				System.out.println ("Time's up, "
					+ (expect - replies)
					+ " replies never arrived");
				break;
			}

			buffer.flip();
			replies++;

			printTime (longBuffer.getLong (0), sa);

			if (replies == expect) {
				System.out.println ("All packets answered");

				break;
			}

			// some replies haven't shown up yet
			System.out.println ("Received " + replies
				+ " of " + expect + " replies");
		}
	
public static voidmain(java.lang.String[] argv)

		TimeClient client = new TimeClient (argv);

		client.sendRequests();
		client.getReplies();
	
protected voidparseArgs(java.lang.String[] argv)

		remoteHosts = new LinkedList();

		for (int i = 0; i < argv.length; i++) {
			String arg = argv [i];

			// send client requests to the given port
			if (arg.equals ("-p")) {
				i++;
				this.port = Integer.parseInt (argv [i]);
				continue;
			}

			// create an address object for the host name
			InetSocketAddress sa = new InetSocketAddress (arg, port);

			// validate that it has an address
			if (sa.getAddress() == null) {
				System.out.println ("Cannot resolve address: "
					+ arg);

				continue;
			}

			remoteHosts.add (sa);
		}
	
protected voidprintTime(long remote1900, java.net.InetSocketAddress sa)

		// local time as seconds since Jan 1, 1970
		long local = System.currentTimeMillis() / 1000;
		// remote time as seconds since Jan 1, 1970
		long remote = remote1900 - DIFF_1900;
		Date remoteDate = new Date (remote * 1000);
		Date localDate = new Date (local * 1000);
		long skew = remote - local;

		System.out.println ("Reply from "
			+ sa.getHostName() + ":" + sa.getPort());
		System.out.println ("  there: " + remoteDate);
		System.out.println ("   here: " + localDate);
		System.out.print ("   skew: ");

		if (skew == 0) {
			System.out.println ("none");
		} else if (skew > 0) {
			System.out.println (skew + " seconds ahead");
		} else {
			System.out.println ((-skew) + " seconds behind");
		}
	
protected java.net.InetSocketAddressreceivePacket(java.nio.channels.DatagramChannel channel, java.nio.ByteBuffer buffer)

		buffer.clear();

		// receive an unsigned 32-bit, big-endian value
		return ((InetSocketAddress) channel.receive (buffer));
	
protected voidsendRequests()

		ByteBuffer buffer = ByteBuffer.allocate (1);
		Iterator it = remoteHosts.iterator();

		while (it.hasNext()) {
			InetSocketAddress sa = (InetSocketAddress) it.next();

			System.out.println ("Requesting time from "
				+ sa.getHostName() + ":" + sa.getPort());

			// make it empty, see RFC868
			buffer.clear().flip();
			// fire and forget
			channel.send (buffer, sa);
		}