Java NIO时间服务

来源:互联网 发布:show java 3.0汉化版 编辑:程序博客网 时间:2024/05/16 09:18

Java NIO时间服务

 

这篇文章内容是另一篇文章《Java 实现基于Redis的分布式锁》的分支. 

 

时间服务包括客户端和服务端, 服务端监听请求 ,若是时间请求,则返回当前服务器的时间, 各个客户端(分布式锁) 都从给服务器获取时间,已达到全局时间一致。

 

共三个类 TimeServer、 TimeClient和TimeClientException,下面是源码:

 

TimeServer.java:

Java代码 
  1. package cc.lixiaohui.lock.time.nio.server;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.InetSocketAddress;  
  5. import java.nio.ByteBuffer;  
  6. import java.nio.channels.SelectionKey;  
  7. import java.nio.channels.Selector;  
  8. import java.nio.channels.ServerSocketChannel;  
  9. import java.nio.channels.SocketChannel;  
  10. import java.util.Iterator;  
  11.   
  12. import org.slf4j.Logger;  
  13. import org.slf4j.LoggerFactory;  
  14.   
  15. /** 
  16.  * 提供简单时间服务的服务器 
  17.  *  
  18.  * @author lixiaohui 
  19.  */  
  20. public class TimeServer {  
  21.   
  22.     private ServerSocketChannel serverChannel;  
  23.   
  24.     private Selector selector;  
  25.   
  26.     private volatile boolean alive = true;  
  27.   
  28.     private static final String TIME_CMD = "time";  
  29.     private static final String HALT_CMD = "halt";  
  30.   
  31.     private static final String ERROR = "error";  
  32.   
  33.     private static final Logger logger = LoggerFactory.getLogger(TimeServer.class);  
  34.   
  35.     public void start(int port) throws IOException {  
  36.         selector = Selector.open();  
  37.   
  38.         serverChannel = ServerSocketChannel.open();  
  39.         serverChannel.configureBlocking(false); // non-blocking mode  
  40.         serverChannel.bind(new InetSocketAddress(port));  
  41.   
  42.         // interested only in accept event  
  43.         serverChannel.register(selector, SelectionKey.OP_ACCEPT);  
  44.   
  45.         while (alive) {  
  46.             try {  
  47.                 if (selector.select() < 0) { // no events  
  48.                     continue;  
  49.                 }  
  50.                 Iterator<SelectionKey> it = selector.selectedKeys().iterator();  
  51.                 while (it.hasNext()) {  
  52.                     SelectionKey key = it.next();  
  53.                     it.remove();  
  54.                     try {  
  55.                         if (!key.isValid())   
  56.                             continue;  
  57.                           
  58.                         if (key.isAcceptable()) { // new channel incoming  
  59.                             SocketChannel ch = ((ServerSocketChannel) key.channel()).accept();  
  60.                             // ignore if register failed  
  61.                             if (!registerChannel(selector, ch, SelectionKey.OP_READ)) {  
  62.                                 continue;  
  63.                             }  
  64.                             logger.info("new channel registered {}", ch.getRemoteAddress().toString());  
  65.                         }  
  66.                         // client request  
  67.                         if (key.isReadable()) {  
  68.                             handleRead(key);  
  69.                         }  
  70.                         if (key.isWritable()) {  
  71.                             handleWrite(key);  
  72.                         }  
  73.                     } catch (IOException e) {  
  74.                         logger.error("{} exception: {}", key.channel(), e);  
  75.                         if (key != null) {  
  76.                             key.cancel();  
  77.                             if (key.channel() != null) {  
  78.                                 key.channel().close();  
  79.                             }  
  80.                         }  
  81.                     }  
  82.                 }  
  83.             } catch (Exception e) {  
  84.                 logger.error("{}", e);  
  85.             }  
  86.         }  
  87.           
  88.         if (selector != null) {  
  89.             try {  
  90.             selector.close();  
  91.             } catch (Exception e) {  
  92.                 logger.error("error occurred when closing selector: e", e);  
  93.             }  
  94.         }  
  95.     }  
  96.   
  97.     private void handleWrite(SelectionKey key) throws IOException {  
  98.         SocketChannel ch = (SocketChannel) key.channel();  
  99.         try {  
  100.             ByteBuffer buf = (ByteBuffer) key.attachment();  
  101.             if (buf != null) {  
  102.                 writeBytesToChannel(ch, buf, key);  
  103.             }  
  104.         } catch (ClassCastException e) {  
  105.             logger.error("{}", e);  
  106.         }  
  107.     }  
  108.   
  109.     private void handleRead(SelectionKey key) throws IOException {  
  110.         SocketChannel ch = (SocketChannel) key.channel();  
  111.         ByteBuffer buffer = ByteBuffer.allocate(16);  
  112.         int read = ch.read(buffer);  
  113.         if (read < 4) { // not a full command, write error back,  
  114.                         // meaning client will send command  
  115.                         // again.  
  116.             writeBytesToChannel(ch, ERROR.getBytes(), key);  
  117.         } else {  
  118.             String cmd = extractCommand(buffer);  
  119.             logger.info("recieve {} request from {}", cmd, ch.getRemoteAddress().toString());  
  120.             if (TIME_CMD.equalsIgnoreCase(cmd)) {  
  121.                 // 回写时间  
  122.                 writeBytesToChannel(ch, String.valueOf(time()).getBytes(), key);  
  123.                 logger.info("write time to {}", ch.getRemoteAddress().toString());  
  124.             } else if (HALT_CMD.equalsIgnoreCase(cmd)) {  
  125.                 // 停止服务  
  126.                 logger.info("stopping timeserver");  
  127.                 stop();  
  128.                 logger.info("timeserver stopped");  
  129.             } else {  
  130.                 writeBytesToChannel(ch, ERROR.getBytes(), key);  
  131.                 logger.warn("unreconized command {}, will discard it.", cmd);  
  132.             }  
  133.         }  
  134.     }  
  135.   
  136.     private String extractCommand(ByteBuffer buffer) {  
  137.         buffer.flip();  
  138.         byte[] array = buffer.array();  
  139.         byte[] newArray = new byte[buffer.remaining()];  
  140.         System.arraycopy(array, buffer.position(), newArray, 0, buffer.remaining());  
  141.         return new String(newArray);  
  142.     }  
  143.   
  144.     private void writeBytesToChannel(SocketChannel ch, byte[] bs, SelectionKey key) throws IOException {  
  145.         ByteBuffer buf = ByteBuffer.wrap(bs);  
  146.         int total = buf.remaining();  
  147.         int write = ch.write(buf);  
  148.         if (write < total) { // didn't wrote all, then write rest when next  
  149.                                 // event triggered  
  150.             key.attach(buf);  
  151.         }  
  152.     }  
  153.   
  154.     private void writeBytesToChannel(SocketChannel ch, ByteBuffer buf, SelectionKey key) throws IOException {  
  155.         if (!buf.hasRemaining()) {  
  156.             return;  
  157.         }  
  158.         int total = buf.remaining();  
  159.         int write = ch.write(buf);  
  160.         if (write < total) { // didn't wrote all, then write rest when next  
  161.                                 // event triggered  
  162.             key.attach(buf);  
  163.         }  
  164.     }  
  165.   
  166.     protected void stop() {  
  167.         alive = false;  
  168.         try {  
  169.             serverChannel.close();  
  170.             selector.close();  
  171.         } catch (IOException e) {  
  172.             // TODO Auto-generated catch block  
  173.             e.printStackTrace();  
  174.         }  
  175.     }  
  176.   
  177.     private boolean registerChannel(Selector sel, SocketChannel sc, int ops) {  
  178.         try {  
  179.             sc.configureBlocking(false);  
  180.             sc.register(sel, ops);  
  181.         } catch (Exception e) {  
  182.             return false;  
  183.         }  
  184.         return true;  
  185.     }  
  186.   
  187.     private long time() {  
  188.         return System.currentTimeMillis();  
  189.     }  
  190.   
  191. }  

 

TimeCient.java:

 

Java代码 
  1. package cc.lixiaohui.lock.time.nio.client;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.InetSocketAddress;  
  5. import java.net.SocketAddress;  
  6. import java.nio.ByteBuffer;  
  7. import java.nio.channels.SocketChannel;  
  8.   
  9. /** 
  10.  * 时间获取客户端 
  11.  * @author lixiaohui 
  12.  * 
  13.  */  
  14. public class TimeClient {  
  15.       
  16.     private static final String TIME_CMD = "time";  
  17.       
  18.     private final SocketAddress address;  
  19.       
  20.     private SocketChannel channel;  
  21.       
  22.     public TimeClient(SocketAddress address) throws IOException {  
  23.         this.address = address;  
  24.         channel = SocketChannel.open(address);  
  25.         channel.configureBlocking(true); // blocking mode  
  26.     }  
  27.       
  28.     /** 
  29.      * @throws TimeClientException when connection with time server is closed. 
  30.      * @return currentTimeMillis in server 
  31.      */  
  32.     public long currentTimeMillis() {  
  33.         try {  
  34.             channel.write(ByteBuffer.wrap(TIME_CMD.getBytes()));  
  35.               
  36.             ByteBuffer buf = ByteBuffer.allocate(64);  
  37.             channel.read(buf);  
  38.               
  39.             buf.flip(); // flip for use of read  
  40.             byte[] bytes = new byte[buf.limit() - buf.position()];  
  41.             System.arraycopy(buf.array(), buf.position(), bytes, 0, bytes.length);  
  42.               
  43.             return Long.parseLong(new String(bytes));  
  44.         } catch(NumberFormatException e) {  
  45.             System.err.println(e);  
  46.             return System.currentTimeMillis();  
  47.         } catch (IOException e) {  
  48.             throw new TimeClientException(address);  
  49.         }  
  50.     }  
  51.       
  52.     /** 
  53.      * close the client, along with its connection with server. 
  54.      */  
  55.     public void close() {  
  56.         try {  
  57.             if (channel != null) {  
  58.                 channel.close();  
  59.             }  
  60.         } catch (IOException e) {  
  61.             e.printStackTrace();  
  62.         }  
  63.           
  64.     }  
  65.       
  66.     public static void main(String[] args) throws IOException {  
  67.         TimeClient client = new TimeClient(new InetSocketAddress("localhost"9999));  
  68.         System.out.println(client.currentTimeMillis());  
  69.         //client.close();  
  70.         System.in.read();  
  71.     }  
  72.   
  73.       
  74. }  

 

TimeClientException.java:

Java代码 
  1. package cc.lixiaohui.lock.time.nio.client;  
  2.   
  3. import java.net.SocketAddress;  
  4.   
  5. public class TimeClientException extends RuntimeException {  
  6.   
  7.     /** 
  8.      *  
  9.      */  
  10.     private static final long serialVersionUID = 1L;  
  11.   
  12.     public TimeClientException() {  
  13.         super();  
  14.         // TODO Auto-generated constructor stub  
  15.     }  
  16.   
  17.     public TimeClientException(String message) {  
  18.         super(message);  
  19.         // TODO Auto-generated constructor stub  
  20.     }  
  21.       
  22.     public TimeClientException(SocketAddress address) {  
  23.         super(address.toString());  
  24.     }  
  25.       
  26. }  
0 0