java非阻塞服务器核心是serversocketchannel配合selector单线程管理多连接;需配置非阻塞、注册op_accept、事件循环中区分处理accept和read,注意buffer翻转、key移除及异常关闭。

Java 中用 ServerSocketChannel 编写非阻塞服务器端,核心是结合 Selector 实现单线程管理多个客户端连接,适合高并发场景。它比传统 ServerSocket 更灵活,但需手动处理 I/O 事件和缓冲区。
初始化 ServerSocketChannel 和 Selector
先创建通道并配置为非阻塞模式,再注册到选择器上监听 OP_ACCEPT 事件:
- 调用
ServerSocketChannel.open()获取通道 - 设置
configureBlocking(false) - 绑定地址:通过
socket().bind(new InetSocketAddress(port)) - 创建
Selector并用register(Selector, SelectionKey.OP_ACCEPT)注册
启动事件循环处理连接和数据
在 while 循环中调用 selector.select() 等待就绪事件,再遍历 selectedKeys() 分发处理:
- 如果是
OP_ACCEPT:调用accept()获取新SocketChannel,设为非阻塞,并注册OP_READ - 如果是
OP_READ:分配ByteBuffer,调用read(buffer);若返回 -1 表示对端关闭,需取消键并关闭通道 - 读完后记得
buffer.flip()再处理内容,最后clear()复用缓冲区
注意资源管理和异常处理
非阻塞 I/O 容易因忽略状态导致逻辑错误或资源泄漏:
- 每次处理完一个 key 后要调用
iterator.remove()避免重复处理 - 关闭通道前应调用
key.cancel(),再关闭底层 socket -
read()或write()可能返回 0(暂时无数据/未写完),不表示错误,需继续等待下一次就绪 - 捕获
IOException(如连接重置)并安全关闭对应 channel
简单回显服务器示例关键片段
以下不是完整代码,而是体现主干逻辑的骨架:
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
server.bind(new InetSocketAddress(8080));
Selector selector = Selector.open();
server.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select();
for (SelectionKey key : selector.selectedKeys()) {
if (key.isAcceptable()) {
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
SocketChannel ch = (SocketChannel) key.channel();
ByteBuffer buf = ByteBuffer.allocate(1024);
int n = ch.read(buf);
if (n > 0) {
buf.flip();
// 处理数据,例如原样返回
ch.write(buf);
} else if (n == -1) {
key.cancel();
ch.close();
}
}
selector.selectedKeys().remove(key);
}
}
不复杂但容易忽略细节,比如缓冲区翻转、key 清理、连接异常判断。写熟了就能支撑万级连接的轻量服务。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











