Java NIO通过非阻塞SocketChannel与ServerSocketChannel配合Selector实现多路复用,服务端注册OP_ACCEPT监听连接、客户端注册OP_CONNECT等待连通,均需手动管理ByteBuffer和事件状态,避免线程阻塞。

Java NIO 用 SocketChannel 和 ServerSocketChannel 实现非阻塞 TCP 通信,核心在于“不等、不卡、多路复用”——通道设为非阻塞,再由 Selector 统一监听多个通道的就绪状态,避免线程空转或阻塞等待。
服务端:监听连接 + 接收数据
服务端需创建 ServerSocketChannel 监听端口,并将它和后续建立的每个 SocketChannel 都注册到同一个 Selector 上:
- 调用
ServerSocketChannel.open()创建通道,用socket().bind()绑定地址端口 - 立即执行
configureBlocking(false)关闭阻塞模式 - 调用
register(selector, SelectionKey.OP_ACCEPT)注册接受连接事件 - 在循环中调用
selector.select()等待就绪事件;一旦有 OP_ACCEPT 就绪,用serverChannel.accept()获取新SocketChannel - 对这个新
SocketChannel同样设为非阻塞,并注册OP_READ,之后它就可被 selector 统一管理读事件
客户端:发起连接 + 发送/接收数据
客户端使用 SocketChannel 主动连接服务端,同样必须是非阻塞的:
- 调用
SocketChannel.open()创建通道,再用connect()发起连接请求 -
connect()在非阻塞模式下会立即返回true(已连上)或false(正在连接中),不能直接认为成功 - 若返回
false,需将该 channel 注册到 selector 上,监听OP_CONNECT事件,等就绪后再调用finishConnect()确认是否真正连通 - 连接成功后,可注册
OP_READ和/或OP_WRITE,通过read(buffer)和write(buffer)收发数据(注意判断返回值:-1 表示对端关闭,0 表示暂无数据/缓冲区满)
关键细节:Buffer 与 事件驱动流程
所有 I/O 操作都围绕 ByteBuffer 进行,且必须配合事件就绪状态来操作:
立即学习“Java免费学习笔记(深入)”;
- 每次
read()前确保 buffer 处于clear()或compact()状态;每次write()前必须flip()切换为读模式 -
Selector.select()返回的是就绪 channel 的数量,要遍历selectedKeys()并逐个处理,处理完记得key.remove()或下次迭代会重复触发 - 一个
SelectionKey对应一个 channel 和其注册的 interestOps;可通过key.channel()取出通道,key.attachment()存放自定义上下文(如用户会话、buffer 引用) - 连接异常、对端关闭、写半包等情况都会反映为特定的就绪状态或 read() 返回值,需主动检查并做清理(如关闭 channel、取消 key)
为什么不用传统 BIO?
传统 ServerSocket.accept() 和 Socket.getInputStream().read() 都是阻塞的,一个连接就要占一个线程。NIO 把“等连接”“等数据”这些耗时等待交给 selector 统一调度,单线程就能高效轮询成百上千个 channel,适合高并发短连接场景。不过它也带来编码复杂度上升——你需要自己管理 buffer、解析协议、处理半包粘包、维护连接状态。


















