SelectionKey 四个状态位表示内核通知的就绪状态:OP_ACCEPT 表示新连接已入全连接队列可 accept;OP_CONNECT 表示 TCP 握手完成需调用 finishConnect() 确认;OP_READ 表示接收缓冲区至少有 1 字节可读;OP_WRITE 表示发送缓冲区有空闲空间可写。

SelectionKey 的四个状态位不是“通道能做什么”,而是“内核已通知:这件事已经完成,现在可以安全执行下一步了”。它们反映的是就绪(ready)状态,不是能力、意愿或缓冲区满/空的瞬时快照。
OP_ACCEPT:服务端监听队列有新连接待 accept
只适用于 ServerSocketChannel。它表示 TCP 三次握手已完成,新连接已进入内核的全连接队列(accept queue),此时调用 serverChannel.accept() 不会阻塞,一定能拿到一个新 SocketChannel。
- 注册前提:通道必须已绑定端口、设为非阻塞,且是 ServerSocketChannel
- 触发时机:客户端发起 connect(),服务端监听 socket 的全连接队列新增条目
- 典型处理:取出 key 对应的 server channel,调用 accept() 创建子 channel;再为该子 channel 注册 OP_READ
OP_CONNECT:客户端 finishConnect() 可安全调用
只适用于主动发起连接的 SocketChannel。它表示 TCP 握手已在内核层面完成,但 Java 层仍需确认——必须调用 channel.finishConnect() 并返回 true,才算真正连通。
- 注册时机:调用 connect() 后立即注册 OP_CONNECT,不可延迟
- 关键检查:就绪后必须调用 finishConnect(),否则可能因假就绪导致后续读写失败
- 后续动作:成功后通常取消 OP_CONNECT,转而注册 OP_READ 或 OP_WRITE 进入数据阶段
OP_READ:接收缓冲区至少有 1 字节可读
对 SocketChannel(常见)或 ServerSocketChannel(极少见)有效。它表示内核已将至少 1 字节数据从网卡复制到用户态 socket 接收缓冲区,此时调用 read() 不会阻塞(但可能只读到部分消息,不保证完整帧)。
- 不是“有完整业务包”,只是“有数据可取”
- 即使只收到半个 TCP 段,也会触发 OP_READ
- 读完后若缓冲区仍有未读数据,下次 select 可能再次就绪;若缓冲区清空,需等待新数据到达才再次触发
OP_WRITE:发送缓冲区有空闲空间可写
常被误解为“可以发数据”,实际含义是“内核发送缓冲区未满,当前 write() 调用大概率不会阻塞”。它通常只在写操作未完成(如 send buffer 满导致 write 返回值
- 默认几乎总是就绪——因为应用层写速远低于网络吞吐,缓冲区常年有空位
- 真正有用场景:当一次 write 写不完全部数据(半包),注册 OP_WRITE 等待缓冲区腾出空间后再续写
- 写完后应立即取消 OP_WRITE,避免无效轮询拖慢 select 效率

















