1、缓冲区Buffer
在NIO库中,所有数据都是用缓冲区(Buffer)处理的。缓冲区实质上是一个数组,通常它是一个字节数组(ByteBuffer),也可以使用其他种类的数组。但是一个缓冲区不仅仅是一个数组,缓冲区提供了对数据的结构化访问以及维护读写位置(limit、position)等信息。
2、通道Channel
Channel是一个通道,可以通过它读取和写入数据。通道与流的不同之处在于通道是双向的,流只是一个方向上移动(一个流必须是InputStream或者OutputStream的子类),而且通道可以同时用于读写。
3、多路复用器Selector
多路复用器提供选择已经就绪的任务的能力。简单来讲,Selector会不断地轮询注册在其上的Channel,如果某个Channel上面有新的TCP连接接入、读和写事件,这个Channel就处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以获得就绪Channel的集合,进行后续的I/O操作。
介绍完NIO几个核心概念,下面来看看服务端与客户端的通信序列图,并用NIO实现一个EchoServer,以对整个流程有更好的理解。
package io.nio; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; 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 java.util.Set; public class NioEchoServer { public static void main(String[] args) { MultiplexerEchoServer server = new MultiplexerEchoServer(8080); new Thread(server).start(); new Thread(new Power(server)).start(); } private static class MultiplexerEchoServer implements Runnable { private Selector selector; private ServerSocketChannel server; private volatile boolean running; public MultiplexerEchoServer(int port) { try { running = true; selector = Selector.open(); server = ServerSocketChannel.open(); server.configureBlocking(false); server.socket().bind(new InetSocketAddress(port), 1024); server.register(selector, SelectionKey.OP_ACCEPT); System.out.println("Server start in:" + port); } catch (IOException e) { e.printStackTrace(); System.exit(1); } } public void stop() { running = false; } @Override public void run() { while (running) { try { selector.select(1000); Set<SelectionKey> readyKeys = selector.selectedKeys(); Iterator<SelectionKey> it = readyKeys.iterator(); SelectionKey key = null; while (it.hasNext()) { key = it.next(); it.remove(); try { handle(key); } catch (Exception e) { if (key != null) { key.cancel(); if (key.channel() != null) { key.channel().close(); } } } } } catch (IOException e) { e.printStackTrace(); } } } private void handle(SelectionKey key) throws IOException { if (key.isValid()) { if (key.isAcceptable()) { ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); SocketChannel sc = ssc.accept(); sc.configureBlocking(false); sc.register(selector, SelectionKey.OP_READ); } if (key.isReadable()) { SocketChannel sc = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); int readBytes = sc.read(buffer); // 大于0:读到了字节、0:没有读到字节、-1:链路已经关闭 if (readBytes > 0) { buffer.flip(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); String msg = new String(bytes, "UTF-8"); System.out.println("Server received:" + msg); doWrite(sc, msg); } else if (readBytes < 0) { key.cancel(); sc.close(); } } } } private void doWrite(SocketChannel channel, String response) throws IOException { if (response != null && response.trim().length() > 0) { byte[] bytes = response.getBytes(); ByteBuffer buffer = ByteBuffer.allocate(bytes.length); buffer.put(bytes); buffer.flip(); channel.write(buffer); } } } private static class Power implements Runnable { private MultiplexerEchoServer server; public Power(MultiplexerEchoServer server) { this.server = server; } @Override public void run() { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); try { String msg = in.readLine(); while (msg != null && !"shutdown".equalsIgnoreCase(msg)) { msg = in.readLine(); } server.stop(); } catch (IOException e) { e.printStackTrace(); } } } }
package io.nio; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set; public class NioEchoClient { public static void main(String[] args) { EchoClient client = new EchoClient("127.0.0.1", 8080); new Thread(client).start(); new Thread(new Writer(client)).start(); } private static class EchoClient implements Runnable { private String host; private int port; private Selector selector; private SocketChannel client; private volatile boolean running; public EchoClient(String host, int port) { try { this.running = true; this.host = host == null ? "127.0.0.1" : host; this.port = port; this.selector = Selector.open(); this.client = SocketChannel.open(); client.configureBlocking(false); } catch (IOException e) { e.printStackTrace(); System.exit(1); } } @Override public void run() { try { doConnect(); } catch (IOException e) { e.printStackTrace(); System.exit(1); } while (running) { try { selector.select(1000); Set<SelectionKey> readyKeys = selector.selectedKeys(); Iterator<SelectionKey> it = readyKeys.iterator(); SelectionKey key = null; while (it.hasNext()) { key = it.next(); it.remove(); try { handle(key); } catch (Exception e) { e.printStackTrace(); if (key != null) { key.cancel(); if (key.channel() != null) { key.channel().close(); } } System.exit(1); } } } catch (Exception e) { e.printStackTrace(); System.exit(1); } } if (selector != null) { try { selector.close(); } catch (IOException e) { e.printStackTrace(); } } } private void handle(SelectionKey key) throws IOException { if (key.isValid()) { SocketChannel sc = (SocketChannel) key.channel(); if (key.isConnectable()) { if (sc.finishConnect()) { sc.register(selector, SelectionKey.OP_READ); } else { System.exit(1); } } if (key.isReadable()) { ByteBuffer buffer = ByteBuffer.allocate(1024); int readBytes = sc.read(buffer); // 大于0:读到了字节、0:没有读到字节、-1:链路已经关闭 if (readBytes > 0) { buffer.flip(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); String msg = new String(bytes, "UTF-8"); System.out.println("Client received:" + msg); } else if (readBytes < 0) { key.cancel(); sc.close(); } } } } private void doConnect() throws IOException { if (client.connect(new InetSocketAddress(host, port))) { client.register(selector, SelectionKey.OP_READ); } else { client.register(selector, SelectionKey.OP_CONNECT); } } public void doWrite(String msg) { byte[] bytes = msg.getBytes(); ByteBuffer buffer = ByteBuffer.allocate(bytes.length); buffer.put(bytes); buffer.flip(); try { client.write(buffer); System.out.println("Cliend send:" + msg); } catch (IOException e) { e.printStackTrace(); } } public void stop() { running = false; } } private static class Writer implements Runnable { private EchoClient client; public Writer(EchoClient client) { this.client = client; } @Override public void run() { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); try { String msg = in.readLine(); while (msg != null && !"quit".equalsIgnoreCase(msg)) { client.doWrite(msg); msg = in.readLine(); } client.stop(); } catch (IOException e) { e.printStackTrace(); } } } }
相关推荐
java_Netty权威指南,详解nio,tcp,http,netty.rar
《Netty权威指南》第1版 是异步非阻塞通信领域的经典之作,基于最新版本Netty 5.0编写,是国内首本深入介绍Netty原理和架构的技术书籍,也是作者多年实战经验的总结和浓缩。在理论方面,讲解了Netty的逻辑架构模型和...
Netty权威指南,可供IT开发者以及正在学习的同学提供学习资料,Netty权威指南PDF书籍
Netty权威指南完整版高清pdf 完整版
, 《Netty权威指南》适合架构师、设计师、软件开发工程师、测试人员和其他对Java NIO框架、Java通信感兴趣的相关人士阅读,相信通过学习《Netty权威指南》,能够熟悉和掌握Netty这一优秀的异步通信框架,实现高可用...
《Netty 权威指南(第2 版)》适合架构师、设计师、软件开发工程师、测试人员以及其他对Java NIO 框架、Netty 感兴趣的相关人士阅读,通过《Netty 权威指南(第2 版)》的学习,读者不仅能够掌握Netty 基础功能的...
Netty权威指南 PDF电子书下载 带目录书签 完整版 Netty权威指南 PDF电子书下载 带目录书签 完整版 高清
《Netty权威指南》适合架构师、设计师、软件开发工程师、测试人员和其他对Java NIO框架、Java通信感兴趣的相关人士阅读,相信通过学习《Netty权威指南》,能够熟悉和掌握Netty这一优秀的异步通信框架,实现高可用...
《Netty 权威指南(第2 版)》适合架构师、设计师、软件开发工程师、测试人员以及其他对JavaNIO 框架、Netty 感兴趣的相关人士阅读,通过《Netty 权威指南(第2 版)》的学习,读者不仅能够掌握Netty 基础功能的使用...
Z00317 NETTY权威指南(第2版)
Netty权威指南中文第二版本,可进一步了解Netty的技术细节
Netty权威 第2版 带书签目录 RPC dubbo Netty权威 第2版 带书签目录 RPC dubbo Netty权威 第2版 带书签目录 RPC dubbo Netty权威 第2版 带书签目录 RPC dubbo Netty权威 第2版 带书签目录 RPC dubbo Netty权威 第2版...
Netty权威指南第二版PDF
Netty权威指南学习工具书,帮你快速了解Netty开发,同时偏向实用性,有着很多的代码例子,可以帮你快速了解和应用
, 《Netty权威指南》适合架构师、设计师、软件开发工程师、测试人员和其他对Java NIO框架、Java通信感兴趣的相关人士阅读,相信通过学习《Netty权威指南》,能够熟悉和掌握Netty这一优秀的异步通信框架,实现高可用...
《Netty 权威指南(第2 版)》适合架构师、设计师、软件开发工程师、测试人员以及其他对Java NIO 框架、Netty 感兴趣的相关人士阅读,通过《Netty 权威指南(第2 版)》的学习,读者不仅能够掌握Netty 基础功能的...
Netty权威指南高清版pdf(带完整书签目录)+源代码 亲测可用
Netty权威指南源码
netty权威指南 官方源码 netty5.0 netty权威指南 官方源码 netty5.0