本例根据RFC 868网络时间协议分别建立了时间协议的客户机和服务器。
1.TimeProtocolConstants类提供提供两个常量静态值:TCP_PORT指定协议的标准TCP端口;EPOCH_OFFSET_MILLIS储存1970年1月1日0时0分0秒(JVM纪年起始时间) 与 1900年1月1日0时0分0秒(协议纪年起始时间) 时间差的毫秒数。
2.TimeProtocolClient类为客户端。getSecondsSinceEpoch方法通过BufferedInputStream的read方法获得协议中的四个时间字节,并当前计算协议时间的毫秒数;getDate方法计算JVM获得时间的毫秒数,并将毫秒数转换为当前的日期和时间;
3.TimeProtocolServer类为服务端。在构造函数中首先建立ServerSocket,启动线程后阻塞;在run里面调用ServerSocket的accept方法生成socket,并调用process方法处理socket;process方法利BufferedOutputStream的write方法将协议中的四个时间字节传给客户机。
测试:
1.客户端单独测试:
I:/jdk/bin>java com.wrox.timeprotocol.TimeProtocolClient time-a.nist.gov
Fri Aug 24 17:06:33 CST 2007
2.服务端与客户端一起测试:
I:/jdk/bin>java com.wrox.timeprotocol.TimeProtocolServer
Fri Aug 24 23:33:20 CST 2007: TimeProtocolServer(37): info: Accepting connection
s on TCP port 37...
Fri Aug 24 23:33:51 CST 2007: TimeProtocolServer(37): info: Connection from loca
lhost:2145
I:/jdk/bin>java com.wrox.timeprotocol.TimeProtocolClient localhost 37
Fri Aug 24 23:33:50 CST 2007
//TimeProtocolConstants
package com.wrox.timeprotocol;
import java.util.Calendar;
// Defines constants used by clients and servers implementing
// the time protocol defined in RFC 868.
public class TimeProtocolConstants
{
// Prevent instantiation
private TimeProtocolConstants() {}
// The time protocol TCP port defined in RFC 868
public static final int TCP_PORT = 37;
// The number of milliseconds between the RFC 868 epoch,
// January 1st 1900, 0:0:0 UTC, and the Java epoch, January
// 1st 1970, 0:0:0 UTC
public static final long EPOCH_OFFSET_MILLIS;
// Computes the epoch offset
static
{
Calendar calendar = Calendar.getInstance(java.util.TimeZone.getTimeZone("UTC"));
calendar.set(1900, Calendar.JANUARY, 1, 0, 0, 0);
EPOCH_OFFSET_MILLIS = Math.abs(calendar.getTime().getTime());
}
}
//TimeProtocolClient
package com.wrox.timeprotocol;
import java.io.*;
import java.net.*;
import java.util.*;
// Static methods for quering time servers using the RFC-868.
public class TimeProtocolClient
{
// Prevent instantiation
private TimeProtocolClient() {}
// Returns the no. of seconds since Jan 1, 1900 00:00:00 UTC
// obtained by the time server on the given address and port.
/**
* @param address - the address of the time server
* @param port - the port of the time server
*
* @exception IOException - if a communications error occured while
* contacting the time server.
* @exception SecurityException - if the client is not permitted to
* connect to the remote server
*/
public static long getSecondsSinceEpoch(InetAddress address, int port) throws SecurityException, IOException
{
Socket socket = new Socket(address, port);
long result;
try
{
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream(),
socket.getReceiveBufferSize());
int b1 = bis.read();
int b2 = bis.read();
int b3 = bis.read();
int b4 = bis.read();
if ((b1 | b2 | b3 | b3) < 0)
{
throw new EOFException("Server didn’t provide a 4-byte value");
}
result = (((long) b1) << 24) + (b2 << 16) + (b3 << 8) + b4;
}
finally
{
socket.close();
}
return (result);
}
/** Returns a Date object encapsulating the current time.
* @param address - the address of the time server
* @param port - the port of the time server
* @exception IOException - error occured while contacting the server
* @exception SecurityException - if the client is not permitted
*/
public static Date getDate(InetAddress address, int port) throws SecurityException, IOException
{
long millis = ((long) getSecondsSinceEpoch(address, port)) * 1000;
return (new Date(millis - TimeProtocolConstants.EPOCH_OFFSET_MILLIS));
}
/** Command-line invocation of the time protocol client. Expects the
* time server host name or address, plus an optional port number used
* to override the default port. The retrieved time is printed to
* standard out adjusted to the local timezone.
*/
public static void main(String[] args)
{
// Parse command-line arguments
InetAddress address = null;
int port = TimeProtocolConstants.TCP_PORT;
try
{
if (args.length == 1)
{
address = InetAddress.getByName(args[0]);
}
else if (args.length == 2)
{
address = InetAddress.getByName(args[0]);
port = Integer.parseInt(args[1]);
}
else
{
System.err.println("Usage: TimeProtocolClient <server> {<port>}");
System.exit(1);
}
}
catch (UnknownHostException e)
{
System.err.println("TimeProtocolClient: unknown host "
+ e.getMessage());
System.exit(1);
}
catch (NumberFormatException e)
{
System.err.println("TimeProtocolClient: Invalid port: "
+ e.getMessage());
System.exit(1);
}
catch (SecurityException e)
{
System.err.println("TimeProtocolClient: permission to resolve host name denied: " + e.getMessage());
System.exit(1);
}
// Retrieve current time from server and print to standard out
try
{
System.out.println(getDate(address, port));
}
catch (java.net.UnknownHostException e)
{
System.err.println("Could not resolve host name: "
+ e.getMessage());
System.exit(1);
}
catch (java.net.ConnectException e)
{
System.err.println("TimeProtocolClient: the time protocol server is not running on "
+ address.getHostName() + ": " + port);
System.exit(1);
}
catch (java.io.IOException e)
{
System.err.println("A communications error occured: "
+ e.getClass().getName() + ": " + e.getMessage());
System.exit(1);
}
catch (SecurityException e)
{
System.err.println("The security manager refused permission to connect to the remote TCP service: "
+ e.getMessage());
System.exit(1);
}
}
}
//TimeProtocolServer
package com.wrox.timeprotocol;
import java.io.*;
import java.net.*;
import java.util.*;
// A network time server supporting RFC-868 over TCP.
public class TimeProtocolServer extends Thread
{
// The TCP server socket used to receive connection requests
protected ServerSocket server = null;
// Used to control termination of the accept thread
protected boolean isActive = true;
// Server socket timeout milliseconds
protected int socketTimeoutMillis = 5000;
/** Construct a new time protocol server
* @see TimeProtocolConstants#TCP_PORT
* @exception IOException - TCP socket could not be created
* @exception SecurityException - permission to create a TCP
* socket is denied.
*/
public TimeProtocolServer() throws SecurityException, IOException
{
this(TimeProtocolConstants.TCP_PORT);
}
/** Constructs a new time server bound to the specified port.
* @param port - the TCP port number used to bind
* @exception IOException - TCP socket could not be created
* @exception SecurityException - permission to create a TCP
* socket is denied.
*/
public TimeProtocolServer(int port) throws SecurityException, IOException
{
server = new ServerSocket(port);
server.setSoTimeout(socketTimeoutMillis);
start();
}
// Logs an error to System.err
public void error(String message, Throwable e)
{
System.err.println(new Date() + ": TimeProtocolServer("
+ server.getLocalPort() + "): error: " + message
+ ": " + e.getClass().getName() + ": " + e.getMessage());
}
// Logs an information message to System.out
public void info(String message)
{
System.out.println(new Date() + ": TimeProtocolServer("
+ server.getLocalPort() + "): info: " + message);
}
// Requests asynchronous termination of the server
public void terminate()
{
isActive = false;
}
/** Processes a new connection. Typically in a separate thread but since we don't read from the client
and comp is trivial, processing can be performed in the same thread.
*/
protected void process(Socket socket)
{
if (socket == null)
{
return;
}
try
{
info("Connection from " + socket.getInetAddress().getHostName()
+ ":" + socket.getPort());
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream(), socket.getSendBufferSize());
// number of seconds since January 1, 1900 0:0:0 UTC
long resultSecs = ((System.currentTimeMillis() +
TimeProtocolConstants.EPOCH_OFFSET_MILLIS) / 1000);
bos.write((int) ((resultSecs >> 24) & 0xFF));
bos.write((int) ((resultSecs >> 16) & 0xFF));
bos.write((int) ((resultSecs >> 8) & 0xFF));
bos.write((int) (resultSecs & 0xFF));
bos.close(); // very important; needed to flush stream contents
}
catch (java.io.IOException e)
{
error("I/O Error", e);
}
finally
{
try
{
socket.close();
}
catch (IOException e)
{
error("Error closing socket", e);
}
}
}
// Server socket accept thread; loops until termination
public void run()
{
info("Accepting connections on TCP port " +
server.getLocalPort() + "...");
while (isActive)
{
Socket socket = null;
try
{
socket = server.accept();
process(socket);
}
catch (java.io.InterruptedIOException e)
{
// Used to periodically check for termination
}
catch (IOException e)
{
error("I/O Error", e);
}
catch (SecurityException e)
{
error("Unauthorized client attemptting to connect", e);
}
catch (Throwable e)
{
error("Unexpected exception", e);
}
}
try
{
server.close();
}
catch (IOException e)
{
error("Error closing server socket", e);
}
info("server thread terminated");
}
/**
* Prints usage to System.err and exits with error code 1
*/
public static void usageExit()
{
System.err.println("Usage: TimeProtocolServer {<port>}");
System.exit(1);
}
// Create a time protocol server. Invocation accepts a single optional port number.
public static void main(String[] args)
{
// Parse command-line arguments
int port = 0;
if (args.length == 0)
{
port = TimeProtocolConstants.TCP_PORT;
}
else if (args.length == 1)
{
try
{
port = Integer.parseInt(args[0]);
}
catch (NumberFormatException e)
{
usageExit();
}
}
else
{
usageExit();
}
// Start time protocol server
TimeProtocolServer server = null;
try
{
server = new TimeProtocolServer(port);
}
catch (java.net.BindException e)
{
System.err.println("The server could not bind to port "
+ port + " (may already be used): " + e.getMessage());
if (port < 1024)
{
System.err.println("Warning: On user-level "
+ "processes cannot bind to ports below 1024");
}
}
catch (java.io.IOException e)
{
System.err.println(e.getMessage());
}
catch (SecurityException e)
{
System.err.println("Permission to bind to port " + port
+ " denied (check security policy): " + e.getMessage());
}
if (server == null) { System.exit(1); }
// Join the server thread, don't have anything else to do
try
{
server.join();
}
catch (InterruptedException e)
{
System.err.println("Error while joined to server thread: "
+ e.getMessage());
System.exit(1);
}
}
}
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/doncai/archive/2007/08/26/1759503.aspx