简介
- 从 Java 1.4 版本开始引入的一个新的 I/O API,可以替代标准的 Java I/O。
- 提供了与标准 I/O 不同的工作方式,核心是 通道(Channel)、缓冲区(Buffer) 和 选择器(Selector)。
- 支持非阻塞 I/O 操作,非常适合处理大量并发连接,是构建高性能网络应用的基础。
- 多路复用的机制,适合构建高性能服务器应用
核心概念
- Channel:类似于流(Stream),但可以双向读写
- Buffer:一个用于存储数据的容器(本质上是一个数组)
- Selector:用于监听多个 Channel 的事件(如连接、读就绪、写就绪)
- 一个线程可以管理多个 Channel,实现单线程处理多路复用,极大地提高了 I/O 效率
代码示例
public class NIOClient {public static void main(String[] args) throws IOException {SocketChannel socketChannel = SocketChannel.open();socketChannel.connect(new InetSocketAddress("localhost", 8080));socketChannel.configureBlocking(false); System.out.println("已连接到服务器 localhost:8080");System.out.println("请输入消息(输入 'quit' 退出):");BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));String userInput;ByteBuffer buffer = ByteBuffer.allocate(1024);while ((userInput = reader.readLine()) != null) {if ("quit".equalsIgnoreCase(userInput)) {break;}byte[] messageBytes = userInput.getBytes();ByteBuffer writeBuffer = ByteBuffer.wrap(messageBytes);socketChannel.write(writeBuffer);System.out.println("已发送: " + userInput);buffer.clear(); int bytesRead = socketChannel.read(buffer);if (bytesRead > 0) {buffer.flip(); byte[] responseBytes = new byte[buffer.remaining()];buffer.get(responseBytes);String response = new String(responseBytes);System.out.println("服务器回复: " + response);}}socketChannel.close();System.out.println("客户端已关闭。");}
}
public class NIOServer {public static void main(String[] args) throws IOException {Selector selector = Selector.open();ServerSocketChannel serverChannel = ServerSocketChannel.open();serverChannel.configureBlocking(false); serverChannel.bind(new InetSocketAddress(8080));serverChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println("NIO 服务器启动,监听端口 8080...");while (true) {int readyChannels = selector.select();if (readyChannels == 0) continue;Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> keyIterator = selectedKeys.iterator();while (keyIterator.hasNext()) {SelectionKey key = keyIterator.next();if (key.isAcceptable()) {ServerSocketChannel server = (ServerSocketChannel) key.channel();SocketChannel clientChannel = server.accept();clientChannel.configureBlocking(false); clientChannel.register(selector, SelectionKey.OP_READ);System.out.println("新客户端连接: " + clientChannel.getRemoteAddress());} else if (key.isReadable()) {SocketChannel clientChannel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(256);int bytesRead = clientChannel.read(buffer);if (bytesRead > 0) {buffer.flip();byte[] data = new byte[buffer.remaining()];buffer.get(data);String message = new String(data);System.out.println("收到消息: " + message);ByteBuffer responseBuffer = ByteBuffer.wrap(("Echo: " + message).getBytes());clientChannel.write(responseBuffer);} else if (bytesRead == -1) {System.out.println("客户端断开: " + clientChannel.getRemoteAddress());clientChannel.close();}}keyIterator.remove();}}}