我为什么会收到一个 CancelledKeyException 异常?

4
我为什么会收到“取消键异常”的错误?有人可以帮我吗?客户端代码哪里出了问题?
java.nio.channels.CancelledKeyException
at sun.nio.ch.SelectionKeyImpl.ensureValid(SelectionKeyImpl.java:73)
at sun.nio.ch.SelectionKeyImpl.interestOps(SelectionKeyImpl.java:82)
at viaNIO.clientasync2.write(clientasync2.java:130)
at viaNIO.clientasync2.run(clientasync2.java:53)
at java.lang.Thread.run(Thread.java:745)

java.nio.channels.CancelledKeyException
at sun.nio.ch.SelectionKeyImpl.ensureValid(SelectionKeyImpl.java:73)
at sun.nio.ch.SelectionKeyImpl.readyOps(SelectionKeyImpl.java:87)
at java.nio.channels.SelectionKey.isReadable(SelectionKey.java:289)
at viaNIO.clientasync2.run(clientasync2.java:55)
at java.lang.Thread.run(Thread.java:745)

以下是客户端的代码:

        while (!Thread.interrupted()) {

            selector.select();

            Iterator<SelectionKey> keys = selector.selectedKeys().iterator();

            while (keys.hasNext()) {
                SelectionKey key = keys.next();
                keys.remove();

                if (key.isValid()) {
                    if (key.isConnectable()) {
                        System.out.println("Connected to the server");
                        connect(key);
                    }
                    if (key.isWritable()) {
                        System.out.println("Writing to the server");
                        write(key);
                    }
                    if (key.isReadable()) {
                        System.out.println("Reading from the server");
                        read(key);
                    }
                }
            }
        }

以下是更新后的代码:

   while (!Thread.interrupted()) {

            selector.select();

            Iterator<SelectionKey> keys = selector.selectedKeys().iterator();

            while (keys.hasNext()) {
                SelectionKey key = keys.next();
                keys.remove();

                if (key.isValid() && key.isConnectable()) {
                    connect(key);
                } else {
                    if (key.isValid() && key.isWritable()) {
                        System.out.println("Writing to the server");
                        write(key);
                    }
                    if (key.isValid() && key.isReadable()) {
                        System.out.println("Reading from the server");
                        read(key);
                    }
                }
            }
        }

这是我用于写方法的代码。
 private void write(SelectionKey key) throws IOException {
    SocketChannel socket = (SocketChannel) key.channel();
    RandomAccessFile aFile = null;
    try {
        File f = new File("D:/test.rar");
        aFile = new RandomAccessFile(f, "r");
        ByteBuffer buffer = ByteBuffer.allocate(300000000);

        FileChannel inChannel = aFile.getChannel();
        while (inChannel.read(buffer) > 0) {
            buffer.flip();
            socket.write(buffer);
            buffer.clear();
        }
        aFile.close();
        socket.close();
        inChannel.close();
        Thread.sleep(1000);

        key.interestOps(SelectionKey.OP_READ);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

读取方法的代码
  private void read(SelectionKey key) throws IOException {
    SocketChannel channel = (SocketChannel) key.channel();
    ByteBuffer readBuffer = ByteBuffer.allocate(1000);
    readBuffer.clear();
    int length;
    try {
        length = channel.read(readBuffer);
    } catch (IOException e) {
        System.out.println("Reading problem, closing connection");
        key.cancel();
        channel.close();
        return;
    }
    if (length == -1) {
        System.out.println("Nothing was read from server");
        channel.close();
        key.cancel();
        return;
    }
    readBuffer.flip();
    byte[] buff = new byte[1024];
    readBuffer.get(buff, 0, length);
    System.out.println("Server said: " + new String(buff));
    if (readCnt != 1) {
        key.interestOps(SelectionKey.OP_WRITE);
        readCnt++;
    } else {
        key.cancel();
        close();
    }
}

连接方法的代码

 private void connect(SelectionKey key) throws IOException {
    SocketChannel channel = (SocketChannel) key.channel();
    if (channel.isConnectionPending()) {
        channel.finishConnect();
    }
    channel.configureBlocking(false);
    channel.register(selector, SelectionKey.OP_READ);
}
1个回答

2
因为在你执行 isReadable() 测试之前,connect()write() 关闭了通道或取消了键。你需要不断重新测试 isValid()。在 isConnectable() 块后面还需要一个 else,因为 OP_CONNECT 无法与 OP_WRITE 或 OP_READ 同时触发:
if (key.isValid() && key.isConnectable()) {
    System.out.println("Connected to the server"); // see below
    connect(key);
} else {
    if (key.isValid() && key.isWritable()) {
        System.out.println("Writing to the server");
        write(key);
    }
    if (key.isValid() && key.isReadable()) {
        System.out.println("Reading from the server");
        read(key);
    }
}

此外,消息"Connected to the server"放错了位置。你即将尝试完成连接:只有当finishConnect()返回true时,你才真正连接上了。

我已经按照你的建议修改了代码,但仍然出现错误'java.nio.channels.CancelledKeyException at sun.nio.ch.SelectionKeyImpl.ensureValid(SelectionKeyImpl.java:73) at sun.nio.ch.SelectionKeyImpl.interestOps(SelectionKeyImpl.java:82) at viaNIO.clientasync2.write(clientasync2.java:128) at viaNIO.clientasync2.run(clientasync2.java:51) at java.lang.Thread.run(Thread.java:745)'。 - jnapor
注意:关闭通道会取消键。在close()之后,您不需要使用cancel() - user207421
非常感谢@EJP。它对我有用。 现在我又遇到了另一个问题。为什么我收到的客户发送的文件副本是不完整的?'文件的实际大小为800MB,但我只收到了25KB。' - jnapor
因为你写文件到套接字的方法完全错误。你应该先按照我上面写的更改clear()compact(),但这确实需要一个完全独立的问题。 - user207421
我已经创建了一个新的问题。我也根据您的建议更新了我的代码,但我仍然得到了不完整的文件。这是链接http://stackoverflow.com/questions/36888298/incomplete-file-copy-java-nio - jnapor
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接