RFC868--时间协议客户机与服务器的实现

本例根据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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值