网络编程-读取服务器网络时间

场景:时间服务器用于Internet众多的网络设备时间同步。时间服务器的默认端口为37,当时间服务器收到客户端的连接请求,立即向返回一个网络时间。
网络时间为一个4字节的无符号整数,它表示当前时间和1900年元月1日0点整的秒数值差。

JTimeClient.java

  1. import java.net.*;  
  2. import java.io.*;  
  3.   
  4. public class JTimeClient {  
  5.   private String server;  //时间服务器   
  6.   private int port;       //端口号   
  7.   
  8.   public JTimeClient(String server) {  
  9.     this(server, 37);//时间服务器默认端口号37   
  10.   }   
  11.     
  12.   public JTimeClient(String server, int port) {  
  13.     this.server = server;  
  14.     this.port = port;  
  15.   }  
  16.     
  17.   //返回网络时间, -1表示出错   
  18.   public long getNetTime() {  
  19.     Socket socket = null;  
  20.     InputStream in = null;  
  21.     try {  
  22.       //连接   
  23.       socket = new Socket(server, port);  
  24.       //时间服务器   
  25.       in = socket.getInputStream( );  
  26.       //读取数据,网络时间为4字节无符号整数,   
  27.       //表示基于1900年元月1日0点的秒数   
  28.       long netTime = 0;  
  29.       for(int i=0; i<4; i++) {  
  30.         netTime = (netTime << 8) | in.read();  
  31.       }  
  32.         
  33.       return netTime;  
  34.     }  
  35.     catch (UnknownHostException e) {  
  36.       //e.printStackTrace();   
  37.     }  
  38.     catch (IOException e) {  
  39.       //e.printStackTrace();   
  40.     }  
  41.     finally {//安全释放资源   
  42.       try {//关闭输入流   
  43.         if(in != null) in.close();  
  44.       } catch (Exception e) {}  
  45.   
  46.       try {//关闭连接   
  47.         if(socket != null) socket.close();  
  48.       } catch (Exception e) {}  
  49.     }  
  50.     return -1;  
  51.   }  
  52.     
  53.   public static void main(String[] args) {  
  54.     JTimeClient timeClient = null;  
  55.       
  56.     if(args.length == 1) {//命令行参数指定时间服务器   
  57.       timeClient = new JTimeClient(args[0]);  
  58.     }  
  59.     else if(args.length == 2) {//指定时间服务器及其端口   
  60.       timeClient = new JTimeClient(args[0], Integer.parseInt(args[1]));  
  61.     }  
  62.     else {  
  63.       System.out.println("Usage: java JTimeClient TimeServer Port");  
  64.       return;  
  65.     }  
  66.   
  67.     System.out.println("Time:" + timeClient.getNetTime());  
  68.   }  
  69. }  
import java.net.*;
import java.io.*;

public class JTimeClient {
  private String server;  //时间服务器
  private int port;       //端口号

  public JTimeClient(String server) {
    this(server, 37);//时间服务器默认端口号37
  }	
  
  public JTimeClient(String server, int port) {
  	this.server = server;
  	this.port = port;
  }
  
  //返回网络时间, -1表示出错
  public long getNetTime() {
  	Socket socket = null;
  	InputStream in = null;
    try {
      //连接
      socket = new Socket(server, port);
      //时间服务器
      in = socket.getInputStream( );
      //读取数据,网络时间为4字节无符号整数,
      //表示基于1900年元月1日0点的秒数
      long netTime = 0;
      for(int i=0; i<4; i++) {
      	netTime = (netTime << 8) | in.read();
      }
      
      return netTime;
    }
    catch (UnknownHostException e) {
   	  //e.printStackTrace();
    }
    catch (IOException e) {
      //e.printStackTrace();
    }
    finally {//安全释放资源
      try {//关闭输入流
        if(in != null) in.close();
      }	catch (Exception e) {}

      try {//关闭连接
        if(socket != null) socket.close();
      }	catch (Exception e) {}
    }
  	return -1;
  }
  
  public static void main(String[] args) {
  	JTimeClient timeClient = null;
  	
	if(args.length == 1) {//命令行参数指定时间服务器
	  timeClient = new JTimeClient(args[0]);
	}
	else if(args.length == 2) {//指定时间服务器及其端口
	  timeClient = new JTimeClient(args[0], Integer.parseInt(args[1]));
	}
	else {
	  System.out.println("Usage: java JTimeClient TimeServer Port");
	  return;
	}

    System.out.println("Time:" + timeClient.getNetTime());
  }
}
如果未启动时间服务器,直接运行本程序结果:
java JTimeClient localhost
Time:-1

轮流工作方式:JTimeServer.java

  1. import java.net.*;  
  2. import java.io.*;  
  3. import java.util.Date;  
  4.   
  5. public class JTimeServer implements Runnable {  
  6.   private int port;  
  7.       
  8.   public JTimeServer() {  
  9.     this(37);//时间服务器默认端口号37   
  10.   }  
  11.   
  12.   public JTimeServer(int port) {  
  13.     this.port = port;  
  14.   }  
  15.     
  16.   public void run() {  
  17.     try {  
  18.       //创建服务器套接字        
  19.       ServerSocket server = new ServerSocket(port);  
  20.       //轮流处理多个客户端的请求   
  21.       while(true) {  
  22.         Socket connection = null;  
  23.         try {  
  24.           //等待客户端连接请求   
  25.           connection = server.accept();  
  26.             
  27.           //利用Date.getTime获取当前系统时间(单位毫秒)   
  28.           //常数2208988800为网络时间和系统时间差   
  29.           Date now = new Date();  
  30.           long netTime = now.getTime()/1000 + 2208988800L;  
  31.           
  32.           byte[] time = new byte[4];  
  33.           for(int i=0; i<4; i++) {  
  34.             time[3 - i] = (byte)(netTime &0x00000000000000FFL);  
  35.             netTime >>= 8;  
  36.           }  
  37.           //获取套接字输入流,并写入网络时间   
  38.           OutputStream out = connection.getOutputStream();  
  39.             
  40.           out.write(time);  
  41.           out.flush();        
  42.         }  
  43.         catch (IOException e) {  
  44.         }  
  45.         finally {//关闭当前连接   
  46.           if (connection != null) connection.close();   
  47.         }  
  48.       }  
  49.     }  
  50.     catch(IOException e) {  
  51.     }  
  52.   }  
  53.     
  54.     
  55.   public static void main(String[] args) {  
  56.     JTimeServer timeServer = null;  
  57.       
  58.     if(args.length == 0) {  
  59.       timeServer = new JTimeServer();  
  60.     }  
  61.     else if(args.length == 1) {//命令行参数指定时间服务器监听端口   
  62.       timeServer = new JTimeServer(Integer.parseInt(args[0]));  
  63.     }  
  64.     else {  
  65.       System.out.println("Usage: java JTimeServer Port");  
  66.       return;  
  67.     }  
  68.       
  69.     (new Thread(timeServer)).start();  
  70.   }  
  71. }  
import java.net.*;
import java.io.*;
import java.util.Date;

public class JTimeServer implements Runnable {
  private int port;
  	
  public JTimeServer() {
  	this(37);//时间服务器默认端口号37
  }

  public JTimeServer(int port) {
  	this.port = port;
  }
  
  public void run() {
  	try {
  	  //创建服务器套接字  	 
      ServerSocket server = new ServerSocket(port);
      //轮流处理多个客户端的请求
  	  while(true) {
        Socket connection = null;
        try {
          //等待客户端连接请求
          connection = server.accept();
          
          //利用Date.getTime获取当前系统时间(单位毫秒)
          //常数2208988800为网络时间和系统时间差
          Date now = new Date();
          long netTime = now.getTime()/1000 + 2208988800L;
        
          byte[] time = new byte[4];
          for(int i=0; i<4; i++) {
          	time[3 - i] = (byte)(netTime &0x00000000000000FFL);
          	netTime >>= 8;
          }
          //获取套接字输入流,并写入网络时间
          OutputStream out = connection.getOutputStream();
		  
          out.write(time);
          out.flush();      
        }
        catch (IOException e) {
        }
        finally {//关闭当前连接
          if (connection != null) connection.close(); 
        }
  	  }
  	}
  	catch(IOException e) {
  	}
  }
  
  
  public static void main(String[] args) {
  	JTimeServer timeServer = null;
  	
	if(args.length == 0) {
	  timeServer = new JTimeServer();
	}
	else if(args.length == 1) {//命令行参数指定时间服务器监听端口
	  timeServer = new JTimeServer(Integer.parseInt(args[0]));
	}
	else {
	  System.out.println("Usage: java JTimeServer Port");
	  return;
	}
	
	(new Thread(timeServer)).start();
  }
}
运行结果:
3558353322

并发工作方式:JTimeServer2.java

  1. import java.net.*;  
  2. import java.io.*;  
  3. import java.util.Date;  
  4. class JTimeThread extends Thread {  
  5.   private Socket connection;    
  6.   public JTimeThread(Socket connection) {  
  7.     this.connection = connection;  
  8.   }    
  9.   public void run() {  
  10.     try {  
  11.       //利用Date.getTime获取当前系统时间(单位毫秒)   
  12.       //常数2208988800为网络时间和系统时间差   
  13.       Date now = new Date();  
  14.       long netTime = now.getTime()/1000 + 2208988800L;  
  15.           
  16.       byte[] time = new byte[4];  
  17.       for(int i=0; i<4; i++) {  
  18.         time[3 - i] = (byte)(netTime &0x00000000000000FFL);  
  19.         netTime >>= 8;  
  20.       }  
  21.       //获取套接字输入流,并写入网络时间   
  22.       OutputStream out = connection.getOutputStream();  
  23.       out.write(time);  
  24.       out.flush();        
  25.     }  
  26.     catch(IOException e) {  
  27.     }    
  28.     finally {//关闭和客户端的连接   
  29.       try {  
  30.         if (connection != null) connection.close();   
  31.       } catch (IOException e) {}  
  32.     }  
  33.   }  
  34. }   
  35. public class JTimeServer2 implements Runnable {  
  36.   private int port;       
  37.   public JTimeServer2() {  
  38.     this(37);//时间服务器默认端口号37   
  39.   }  
  40.   public JTimeServer2(int port) {  
  41.     this.port = port;  
  42.   }    
  43.   public void run() {  
  44.     ServerSocket server = null;  
  45.     try {  
  46.       //创建服务器套接字        
  47.       server = new ServerSocket(port);  
  48.       //轮流处理多个客户端的请求   
  49.       while(true) {  
  50.         try {  
  51.           //等待客户端连接请求   
  52.           Socket connection = server.accept();  
  53.           //创建并启动一个JTimeThread线程来服务客户端请求   
  54.           (new JTimeThread(connection)).start();  
  55.         }  
  56.         catch (IOException e) {  
  57.         }  
  58.       }  
  59.     }  
  60.     catch(IOException e) {  
  61.     }  
  62.     finally { //关闭服务器Socket   
  63.       try {  
  64.         if(null != server) server.close();  
  65.       } catch (IOException e) {}  
  66.     }  
  67.   }    
  68.   public static void main(String[] args) {  
  69.     JTimeServer2 timeServer = null;       
  70.     if(args.length == 0) {  
  71.       timeServer = new JTimeServer2();  
  72.     }  
  73.     else if(args.length == 1) {//命令行参数指定时间服务器监听端口   
  74.       timeServer = new JTimeServer2(Integer.parseInt(args[0]));  
  75.     }  
  76.     else {  
  77.       System.out.println("Usage: java JTimeServer2 Port");  
  78.       return;  
  79.     }     
  80.     (new Thread(timeServer)).start();  
  81.   }  
  82. }  
import java.net.*;
import java.io.*;
import java.util.Date;
class JTimeThread extends Thread {
  private Socket connection;  
  public JTimeThread(Socket connection) {
  	this.connection = connection;
  }  
  public void run() {
  	try {
      //利用Date.getTime获取当前系统时间(单位毫秒)
      //常数2208988800为网络时间和系统时间差
      Date now = new Date();
      long netTime = now.getTime()/1000 + 2208988800L;
        
      byte[] time = new byte[4];
      for(int i=0; i<4; i++) {
        time[3 - i] = (byte)(netTime &0x00000000000000FFL);
        netTime >>= 8;
      }
      //获取套接字输入流,并写入网络时间
      OutputStream out = connection.getOutputStream();
      out.write(time);
      out.flush();      
  	}
  	catch(IOException e) {
  	}  
    finally {//关闭和客户端的连接
      try {
        if (connection != null) connection.close(); 
      } catch (IOException e) {}
    }
  }
} 
public class JTimeServer2 implements Runnable {
  private int port;  	
  public JTimeServer2() {
  	this(37);//时间服务器默认端口号37
  }
  public JTimeServer2(int port) {
  	this.port = port;
  }  
  public void run() {
  	ServerSocket server = null;
  	try {
  	  //创建服务器套接字  	 
      server = new ServerSocket(port);
      //轮流处理多个客户端的请求
  	  while(true) {
        try {
          //等待客户端连接请求
          Socket connection = server.accept();
          //创建并启动一个JTimeThread线程来服务客户端请求
          (new JTimeThread(connection)).start();
        }
        catch (IOException e) {
        }
  	  }
  	}
  	catch(IOException e) {
  	}
  	finally { //关闭服务器Socket
      try {
        if(null != server) server.close();
      } catch (IOException e) {}
  	}
  }  
  public static void main(String[] args) {
  	JTimeServer2 timeServer = null;  	
	if(args.length == 0) {
	  timeServer = new JTimeServer2();
	}
	else if(args.length == 1) {//命令行参数指定时间服务器监听端口
	  timeServer = new JTimeServer2(Integer.parseInt(args[0]));
	}
	else {
	  System.out.println("Usage: java JTimeServer2 Port");
	  return;
	}	
	(new Thread(timeServer)).start();
  }
}

Date.getTime()获取当前系统时间,这是一个基于1927元月1日0点的long型毫秒数。

PS注意:
在向Socket写入数据的时候,我们还要注意一个非常重要的细节:网络字节顺序为高字节在前。

Java 新IO再进化Selector创建一个非阻塞的服务器,此服务器向客户端返回当前的系统时间。

  1. import java.net.InetSocketAddress ;  
  2. import java.net.ServerSocket ;  
  3. import java.util.Set ;  
  4. import java.util.Iterator ;  
  5. import java.util.Date ;  
  6. import java.nio.channels.ServerSocketChannel ;  
  7. import java.nio.ByteBuffer ;  
  8. import java.nio.channels.SocketChannel ;  
  9. import java.nio.channels.Selector  ;  
  10. import java.nio.channels.SelectionKey  ;  
  11. public class DateServer{  
  12.     public static void main(String args[]) throws Exception {  
  13.         int ports[] = {8000,8001,8002,8003,8005,8006} ; // 表示五个监听端口   
  14.         Selector selector = Selector.open() ;   // 通过open()方法找到Selector   
  15.         for(int i=0;i<ports.length;i++){  
  16.             ServerSocketChannel initSer = null ;  
  17.             initSer = ServerSocketChannel.open() ;  // 打开服务器的通道   
  18.             initSer.configureBlocking(false) ;  // 服务器配置为非阻塞   
  19.             ServerSocket initSock = initSer.socket() ;  
  20.             InetSocketAddress address = null ;  
  21.             address = new InetSocketAddress(ports[i]) ; // 实例化绑定地址   
  22.             initSock.bind(address) ;    // 进行服务的绑定   
  23.             initSer.register(selector,SelectionKey.OP_ACCEPT) ; // 等待连接   
  24.             System.out.println("服务器运行,在" + ports[i] + "端口监听。") ;  
  25.         }  
  26.         // 要接收全部生成的key,并通过连接进行判断是否获取客户端的输出   
  27.         int keysAdd = 0 ;  
  28.         while((keysAdd=selector.select())>0){    // 选择一组键,并且相应的通道已经准备就绪   
  29.             Set<SelectionKey> selectedKeys = selector.selectedKeys() ;// 取出全部生成的key   
  30.             Iterator<SelectionKey> iter = selectedKeys.iterator() ;  
  31.             while(iter.hasNext()){  
  32.                 SelectionKey key = iter.next() ;    // 取出每一个key   
  33.                 if(key.isAcceptable()){  
  34.                     ServerSocketChannel server = (ServerSocketChannel)key.channel() ;  
  35.                     SocketChannel client = server.accept() ;    // 接收新连接   
  36.                     client.configureBlocking(false) ;// 配置为非阻塞   
  37.                     ByteBuffer outBuf = ByteBuffer.allocateDirect(1024) ;   //   
  38.                     outBuf.put(("当前的时间为:" + new Date()).getBytes()) ;   // 向缓冲区中设置内容   
  39.                     outBuf.flip() ;  
  40.                     client.write(outBuf) ;  // 输出内容   
  41.                     client.close() ;    // 关闭   
  42.                 }  
  43.             }  
  44.             selectedKeys.clear() ;  // 清楚全部的key   
  45.         }  
  46.           
  47.     }  
  48. }  
import java.net.InetSocketAddress ;
import java.net.ServerSocket ;
import java.util.Set ;
import java.util.Iterator ;
import java.util.Date ;
import java.nio.channels.ServerSocketChannel ;
import java.nio.ByteBuffer ;
import java.nio.channels.SocketChannel ;
import java.nio.channels.Selector  ;
import java.nio.channels.SelectionKey  ;
public class DateServer{
	public static void main(String args[]) throws Exception {
		int ports[] = {8000,8001,8002,8003,8005,8006} ; // 表示五个监听端口
		Selector selector = Selector.open() ;	// 通过open()方法找到Selector
		for(int i=0;i<ports.length;i++){
			ServerSocketChannel initSer = null ;
			initSer = ServerSocketChannel.open() ;	// 打开服务器的通道
			initSer.configureBlocking(false) ;	// 服务器配置为非阻塞
			ServerSocket initSock = initSer.socket() ;
			InetSocketAddress address = null ;
			address = new InetSocketAddress(ports[i]) ;	// 实例化绑定地址
			initSock.bind(address) ;	// 进行服务的绑定
			initSer.register(selector,SelectionKey.OP_ACCEPT) ;	// 等待连接
			System.out.println("服务器运行,在" + ports[i] + "端口监听。") ;
		}
		// 要接收全部生成的key,并通过连接进行判断是否获取客户端的输出
		int keysAdd = 0 ;
		while((keysAdd=selector.select())>0){	// 选择一组键,并且相应的通道已经准备就绪
			Set<SelectionKey> selectedKeys = selector.selectedKeys() ;// 取出全部生成的key
			Iterator<SelectionKey> iter = selectedKeys.iterator() ;
			while(iter.hasNext()){
				SelectionKey key = iter.next() ;	// 取出每一个key
				if(key.isAcceptable()){
					ServerSocketChannel server = (ServerSocketChannel)key.channel() ;
					SocketChannel client = server.accept() ;	// 接收新连接
					client.configureBlocking(false) ;// 配置为非阻塞
					ByteBuffer outBuf = ByteBuffer.allocateDirect(1024) ;	//
					outBuf.put(("当前的时间为:" + new Date()).getBytes()) ;	// 向缓冲区中设置内容
					outBuf.flip() ;
					client.write(outBuf) ;	// 输出内容
					client.close() ;	// 关闭
				}
			}
			selectedKeys.clear() ;	// 清楚全部的key
		}
		
	}
}

注意:服务器运行后并不会像传统的Socket那样立刻关闭服务器,而是会继续等待下一次的连接。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值