socketchannel 必须在注册 selector 前调用 configureblocking(false),否则抛出 illegalblockingmodeexception;客户端需监听 op_connect 并调用 finishconnect() 确认连接,服务端 serversocketchannel 也须设为非阻塞。

在 Java 中,SocketChannel 默认是阻塞模式的,要设置为非阻塞模式,必须在调用 configureBlocking(false) 之前完成通道的创建和连接(或绑定)初始化,并且该通道必须是通过 Selector 配合使用的——因为非阻塞 I/O 的核心机制依赖于选择器轮询就绪事件。
必须在注册 Selector 前调用 configureBlocking(false)
这是最关键的一步。一旦 SocketChannel 被注册到 Selector 上,就不能再修改其阻塞状态;否则会抛出 IllegalBlockingModeException。正确顺序如下:
- 通过
SocketChannel.open()创建通道 - 立即调用
channel.configureBlocking(false) - 然后调用
channel.connect(...)(客户端)或channel.bind(...)+channel.listen(...)(服务端) - 最后才调用
channel.register(selector, ops, attachment)
客户端示例:非阻塞连接与读写
客户端建立非阻塞连接时,connect() 不会等待 TCP 三次握手完成,而是立即返回 false(表示连接尚未就绪)。你需要监听 SelectionKey.OP_CONNECT 事件,在就绪后调用 finishConnect() 确认连接成功:
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(new InetSocketAddress("example.com", 80));
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_CONNECT);
// 后续在 select 循环中处理
while (selector.select() > 0) {
Set<selectionkey> keys = selector.selectedKeys();
Iterator<selectionkey> iter = keys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
iter.remove();
if (key.isConnectable()) {
SocketChannel ch = (SocketChannel) key.channel();
if (ch.finishConnect()) {
System.out.println("Connected!");
key.interestOps(SelectionKey.OP_READ); // 切换为读事件
}
}
}
}</selectionkey></selectionkey>
服务端注意:ServerSocketChannel 同样需非阻塞
如果你用 SocketChannel 处理服务端的客户端连接,那么它的父通道 ServerSocketChannel 也必须是非阻塞的:
ServerSocketChannel.open().configureBlocking(false)- 绑定地址并调用
register(selector, OP_ACCEPT) - 当收到
OP_ACCEPT事件时,调用serverChannel.accept()获取新SocketChannel - 对每个新获得的
SocketChannel,同样执行configureBlocking(false)和register(...)
常见错误提醒
以下操作会导致运行时异常或逻辑错误:
- 在已注册到
Selector的通道上调用configureBlocking(true)或再次设为false - 未检查
finishConnect()返回值就直接读写(可能抛出NotYetConnectedException) - 非阻塞通道调用
read(ByteBuffer)或write(ByteBuffer)时,返回值可能是 0 或 -1,需按规范处理(如 -1 表示对端关闭) - 忘记在每次
select()后清理selectedKeys()集合,导致重复处理
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











