Java NIO时间服务
这篇文章内容是另一篇文章《Java 实现基于Redis的分布式锁》的分支.
时间服务包括客户端和服务端, 服务端监听请求 ,若是时间请求,则返回当前服务器的时间, 各个客户端(分布式锁) 都从给服务器获取时间,已达到全局时间一致。
共三个类 TimeServer、 TimeClient和TimeClientException,下面是源码:
TimeServer.java:
package cc.lixiaohui.lock.time.nio.server; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 提供简单时间服务的服务器 * * @author lixiaohui */ public class TimeServer { private ServerSocketChannel serverChannel; private Selector selector; private volatile boolean alive = true; private static final String TIME_CMD = "time"; private static final String HALT_CMD = "halt"; private static final String ERROR = "error"; private static final Logger logger = LoggerFactory.getLogger(TimeServer.class); public void start(int port) throws IOException { selector = Selector.open(); serverChannel = ServerSocketChannel.open(); serverChannel.configureBlocking(false); // non-blocking mode serverChannel.bind(new InetSocketAddress(port)); // interested only in accept event serverChannel.register(selector, SelectionKey.OP_ACCEPT); while (alive) { try { if (selector.select() < 0) { // no events continue; } Iterator<SelectionKey> it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey key = it.next(); it.remove(); try { if (!key.isValid()) continue; if (key.isAcceptable()) { // new channel incoming SocketChannel ch = ((ServerSocketChannel) key.channel()).accept(); // ignore if register failed if (!registerChannel(selector, ch, SelectionKey.OP_READ)) { continue; } logger.info("new channel registered {}", ch.getRemoteAddress().toString()); } // client request if (key.isReadable()) { handleRead(key); } if (key.isWritable()) { handleWrite(key); } } catch (IOException e) { logger.error("{} exception: {}", key.channel(), e); if (key != null) { key.cancel(); if (key.channel() != null) { key.channel().close(); } } } } } catch (Exception e) { logger.error("{}", e); } } if (selector != null) { try { selector.close(); } catch (Exception e) { logger.error("error occurred when closing selector: e", e); } } } private void handleWrite(SelectionKey key) throws IOException { SocketChannel ch = (SocketChannel) key.channel(); try { ByteBuffer buf = (ByteBuffer) key.attachment(); if (buf != null) { writeBytesToChannel(ch, buf, key); } } catch (ClassCastException e) { logger.error("{}", e); } } private void handleRead(SelectionKey key) throws IOException { SocketChannel ch = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(16); int read = ch.read(buffer); if (read < 4) { // not a full command, write error back, // meaning client will send command // again. writeBytesToChannel(ch, ERROR.getBytes(), key); } else { String cmd = extractCommand(buffer); logger.info("recieve {} request from {}", cmd, ch.getRemoteAddress().toString()); if (TIME_CMD.equalsIgnoreCase(cmd)) { // 回写时间 writeBytesToChannel(ch, String.valueOf(time()).getBytes(), key); logger.info("write time to {}", ch.getRemoteAddress().toString()); } else if (HALT_CMD.equalsIgnoreCase(cmd)) { // 停止服务 logger.info("stopping timeserver"); stop(); logger.info("timeserver stopped"); } else { writeBytesToChannel(ch, ERROR.getBytes(), key); logger.warn("unreconized command {}, will discard it.", cmd); } } } private String extractCommand(ByteBuffer buffer) { buffer.flip(); byte[] array = buffer.array(); byte[] newArray = new byte[buffer.remaining()]; System.arraycopy(array, buffer.position(), newArray, 0, buffer.remaining()); return new String(newArray); } private void writeBytesToChannel(SocketChannel ch, byte[] bs, SelectionKey key) throws IOException { ByteBuffer buf = ByteBuffer.wrap(bs); int total = buf.remaining(); int write = ch.write(buf); if (write < total) { // didn't wrote all, then write rest when next // event triggered key.attach(buf); } } private void writeBytesToChannel(SocketChannel ch, ByteBuffer buf, SelectionKey key) throws IOException { if (!buf.hasRemaining()) { return; } int total = buf.remaining(); int write = ch.write(buf); if (write < total) { // didn't wrote all, then write rest when next // event triggered key.attach(buf); } } protected void stop() { alive = false; try { serverChannel.close(); selector.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private boolean registerChannel(Selector sel, SocketChannel sc, int ops) { try { sc.configureBlocking(false); sc.register(sel, ops); } catch (Exception e) { return false; } return true; } private long time() { return System.currentTimeMillis(); } }
TimeCient.java:
package cc.lixiaohui.lock.time.nio.client; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; /** * 时间获取客户端 * @author lixiaohui * */ public class TimeClient { private static final String TIME_CMD = "time"; private final SocketAddress address; private SocketChannel channel; public TimeClient(SocketAddress address) throws IOException { this.address = address; channel = SocketChannel.open(address); channel.configureBlocking(true); // blocking mode } /** * @throws TimeClientException when connection with time server is closed. * @return currentTimeMillis in server */ public long currentTimeMillis() { try { channel.write(ByteBuffer.wrap(TIME_CMD.getBytes())); ByteBuffer buf = ByteBuffer.allocate(64); channel.read(buf); buf.flip(); // flip for use of read byte[] bytes = new byte[buf.limit() - buf.position()]; System.arraycopy(buf.array(), buf.position(), bytes, 0, bytes.length); return Long.parseLong(new String(bytes)); } catch(NumberFormatException e) { System.err.println(e); return System.currentTimeMillis(); } catch (IOException e) { throw new TimeClientException(address); } } /** * close the client, along with its connection with server. */ public void close() { try { if (channel != null) { channel.close(); } } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) throws IOException { TimeClient client = new TimeClient(new InetSocketAddress("localhost", 9999)); System.out.println(client.currentTimeMillis()); //client.close(); System.in.read(); } }
TimeClientException.java:
package cc.lixiaohui.lock.time.nio.client; import java.net.SocketAddress; public class TimeClientException extends RuntimeException { /** * */ private static final long serialVersionUID = 1L; public TimeClientException() { super(); // TODO Auto-generated constructor stub } public TimeClientException(String message) { super(message); // TODO Auto-generated constructor stub } public TimeClientException(SocketAddress address) { super(address.toString()); } }
相关推荐
Java NIO(New Input/Output)是Java标准库提供的一种I/O模型,它与传统的 Blocking I/O(IO)相比,提供了更加高效的数据传输方式。在Java NIO中,"新"主要体现在非阻塞和多路复用这两个特性上,这使得NIO更适合于...
Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java...然而,NIO的API相对复杂,学习曲线较陡峭,需要花费一定时间去理解和实践。通过熟练掌握Java NIO,开发者可以构建出更加高效、可扩展的系统。
在Java中,可以使用java.nio.file包下的Files和Paths类来列出目录中的文件和子目录,获取文件的基本信息,如大小、修改时间等。 在实际开发中,我们还需要考虑错误处理、安全性(如权限控制)、性能优化(如批量...
- 对实时性要求较高的应用,因为NIO的非阻塞特性可以减少等待时间。 总之,这个Java NIO IM实例是一个很好的学习资源,它演示了如何利用NIO进行高效的网络通信。通过深入理解并实践这个示例,开发者可以更好地掌握...
在NIO的上下文中,注解可能被用于配置NIO相关的服务,如网络服务器的端口设置。 再来说说Applet,它是Java的一种小程序,可以在浏览器中运行。然而,由于安全性和现代Web技术的发展,Applet的使用已经逐渐减少。在...
在性能对比测试中,实验结果表明,基于NIO的新服务器模型在处理高并发时,平均响应时间仅为2.09毫秒,且CPU占用率保持在68.5%的较低水平。与之相比,传统IO服务器模型在处理并发流量时,不仅性能上无法达到新模型的...
### Java NIO原理 图文分析及代码实现 #### 前言 在深入探讨Java NIO之前,我们先简要回顾一下NIO的概念及其引入的原因。随着互联网的发展,越来越多的应用程序需要处理高并发的网络连接请求。传统的阻塞I/O模型在...
### Java NIO 在并发型服务器设计中的应用 #### 引言 随着计算机硬件技术的不断发展,尤其是多处理器架构的普及、网络技术的进步以及...此外,NIO还优化了资源利用率,减少了线程空闲时间,从而提升了整体性能。
`io与nio性能测试.txt`文件可能包含了实际运行的性能测试结果,包括平均时间、吞吐量等指标。这种测试可能涉及多次运行,以减少偶然因素的影响。通常,NIO在处理大量数据或并发I/O操作时表现更好,因为它允许程序在...
基于Java NIO的反应器模式设计与实现,可以大幅提升网络服务器的性能,通过非阻塞IO、事件驱动、选择器等机制,高效地处理高并发的数据传输任务,并且优化了线程资源的使用,减少了线程上下文切换的时间开销,同时还...
Java NIO(New IO)是Java 1.4版本引入的一个新特性,它为Java...这个项目展示了如何利用Java NIO构建高性能的网络服务,并结合现代数据库技术实现用户认证,对于学习Java NIO以及分布式系统的开发具有很好的参考价值。
Java NIO,全称为New Input/Output,是Java在1.4版本引入的一个新特性,为Java程序员提供了更高效的数据传输方式。与传统的IO模型相比,NIO具有非阻塞、多路复用等优点,尤其适用于高并发、低延迟的网络应用。本文将...
NIO可以提高数据库连接池的效率,减少线程等待时间,从而提高整体系统性能。Eran Toch的讲座可能涵盖了使用NIO进行批量数据传输、优化SQL查询等方面。 `session4-extra.ppt`可能是一场技术研讨会的补充材料,详细...