You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何SelectionKey.attachment()返回null?Java NIO服务端空指针问题

问题分析:SelectionKey.attachment()返回null的原因

初始代码的核心错误

在最初的register方法中,你将ClientData附加到了ServerSocketChannel对应的SelectionKey(即传入register的key参数)上,但readBytes方法处理的是SocketChannel对应的SelectionKey——这是两个完全独立的SelectionKey,因此在readBytes中调用key.attachment()自然会返回null。

更新后代码的错误点

更新后的register方法逻辑正确(将ClientData附加到了SocketChannel的SelectionKey上),但readBytes方法犯了两个关键错误:

  1. 多余的重复注册:你在readBytes中调用client.register(key.selector(), SelectionKey.OP_WRITE)来获取clientKey,但传入readBytes的key参数本身就是该SocketChannel对应的SelectionKey,完全不需要重新注册。
  2. 误解SelectionKey的归属:即使重复注册返回的是原SelectionKey,这种操作不仅冗余,还可能因逻辑混淆导致你忽略了原本就带attachment的传入key。

为什么更新后仍返回null?

在更新后的readBytes代码中,若SocketChannel已注册到Selector,register方法会返回原有的SelectionKey(保留原attachment),但你错误地绕开了传入的、已带attachment的key,转而通过重复注册获取key——这种操作毫无必要,且若存在极端情况(如原key被意外取消),就会导致获取到的key无attachment。

修复后的正确代码

修正的readBytes方法

直接使用传入的key获取attachment,修改兴趣操作无需重新注册:

private void readBytes(SelectionKey key) throws IOException {
    SocketChannel client = (SocketChannel) key.channel();
    var data = (ClientData) key.attachment();
    // 读取数据,注意处理客户端关闭的情况(返回-1)
    int bytesRead = client.read(data.buffer);
    if (bytesRead == -1) {
        key.cancel();
        client.close();
        return;
    }
    // 修改兴趣操作为OP_WRITE
    key.interestOps(SelectionKey.OP_WRITE);
}

保持正确的register方法

private void register(SelectionKey key) throws IOException {
    var ssc = (ServerSocketChannel) key.channel();
    var client = ssc.accept();
    client.configureBlocking(false);
    SelectionKey clientKey = client.register(key.selector(), SelectionKey.OP_READ);
    clientKey.attach(new ClientData());
}

内容的提问来源于stack exchange,提问作者msuny-c

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 04:37:05