原理图:

服务端:
package xyz.idoly.demo.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
public class NioServer {
private static final int PORT = 8080;
public static void main(String[] args) throws IOException {
// 1. 创建 ServerSocketChannel 并绑定端口
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(PORT));
serverChannel.configureBlocking(false); // 非阻塞模式
// 2. 创建 Selector 并注册 ServerSocketChannel
Selector selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("NIO 服务器已启动,监听端口:" + PORT);
// 3. 事件循环处理
while (true) {
selector.select(); // 阻塞等待事件
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove(); // 处理后删除,避免重复处理
if (key.isAcceptable()) {
handleAccept(serverChannel, selector);
} else if (key.isReadable()) {
handleRead(key);
}
}
}
}
private static void handleAccept(ServerSocketChannel serverChannel, Selector selector) throws IOException {
SocketChannel clientChannel = serverChannel.accept(); // 接收连接
clientChannel.configureBlocking(false);
clientChannel.register(selector, SelectionKey.OP_READ);
System.out.println("新客户端连接:" + clientChannel.getRemoteAddress());
}
private static void handleRead(SelectionKey key) throws IOException {
SocketChannel clientChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = clientChannel.read(buffer);
if (bytesRead == -1) {
clientChannel.close(); // 关闭连接
System.out.println("客户端断开连接");
return;
}
buffer.flip();
String message = new String(buffer.array(), 0, buffer.limit());
System.out.println("收到消息:" + message);
// 回显消息
buffer.rewind();
clientChannel.write(buffer);
}
}
NIO 服务器已启动,监听端口:8080
新客户端连接:/127.0.0.1:56740
收到消息:Hello, NIO Server!
客户端断开连接
客户端:
package xyz.idoly.demo.nio;
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.SocketChannel;
import java.util.Iterator;
public class NioClient {
private static final String SERVER_HOST = "127.0.0.1";
private static final int SERVER_PORT = 8080;
public static void main(String[] args) throws IOException {
// 1. 打开 SocketChannel 并设置为非阻塞模式
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
// 2. 打开 Selector,并注册 CONNECT 事件
Selector selector = Selector.open();
socketChannel.register(selector, SelectionKey.OP_CONNECT);
socketChannel.connect(new InetSocketAddress(SERVER_HOST, SERVER_PORT));
// 3. 监听事件
while (true) {
selector.select(); // 阻塞直到有事件就绪
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove(); // 避免重复处理
if (key.isConnectable()) {
handleConnect(key);
} else if (key.isWritable()) {
handleWrite(key);
} else if (key.isReadable()) {
handleRead(key);
}
}
}
}
private static void handleConnect(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
if (channel.finishConnect()) { // 完成连接
System.out.println("连接服务器成功!");
channel.configureBlocking(false);
// 连接成功后,注册 WRITE 事件,准备发送数据
channel.register(key.selector(), SelectionKey.OP_WRITE);
}
}
private static void handleWrite(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
String message = "Hello, NIO Server!";
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
channel.write(buffer);
System.out.println("发送消息:" + message);
// 发送完毕后,注册 READ 事件,等待服务器响应
channel.register(key.selector(), SelectionKey.OP_READ);
}
private static void handleRead(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = channel.read(buffer);
if (bytesRead > 0) {
buffer.flip();
String response = new String(buffer.array(), 0, buffer.limit());
System.out.println("收到服务器响应:" + response);
// 读取完成后,关闭通道
channel.close();
}
}
}
连接服务器成功!
发送消息:Hello, NIO Server!
收到服务器响应:Hello, NIO Server!