4

Why do I get an error of Cancelled Key Exception? Can anyone please help me? What part of the code of the client went wrong?

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)

Here is the code for the Client:

        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);
                    }
                }
            }
        }

Here is the updated Code:

   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);
                    }
                }
            }
        }

This is also my code for the write method

 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();
    }
}

The code for the read method

  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();
    }
}

The code for the connect method

 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);
}
jnapor
  • 63
  • 1
  • 1
  • 9

1 Answers1

2

Because either connect() or write() closed the channel or cancelled the key before you got to the isReadable() test. You need to keep re-testing isValid(). You also need an else after the isConnectable() block, as OP_CONNECT cannot fire along with either of OP_WRITE or 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);
    }
}

Also the message "Connected to the server" is in the wrong place. You are about to attempt to complete the connection: if and only if finishConnect() returns true are you actually connected.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • I already changed my code to the way you advised but I still get an error '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 Apr 27 '16 at 03:18
  • So the channel is closed or the key was cancelled. You'll have to post your new code, including the `connect(),` `write()`, and `read()` methods. Edit it into your question. Why are you checking the `interestOps` again in the `write()` method? – user207421 Apr 27 '16 at 03:41
  • I already edited my post @EJP. Can you please help where my code went wrong? Thanks – jnapor Apr 27 '16 at 08:17
  • Exactly as I said. You are closing the socket in your `write()` method and then calling `interestOps()` as though it was still open. It isn't. It doesn't begin to make sense. NB Your code around `finishConnect()` is incorrect. See what I wrote above. *If and only if* `finishConnect()` returns `true` the channel is connected. You are ignoring the return code. The `Thread.sleep()` calls in your code are pointless, and `clear()` should be `compact()`. – user207421 Apr 27 '16 at 10:03
  • NB closing a channel cancels the key. You don't need `cancel()` after `close()`. – user207421 Apr 27 '16 at 10:17
  • Thanks alot @EJP. It worked for me. Now I also the another problem. **Why is it that I received an incomplete file copy that was sent by the client?** 'Actual size of the file is 800MB but I only received 25KB.' – jnapor Apr 27 '16 at 10:58
  • Because your approach to writing the file to the socket is completely wrong. You should start by changing `clear()` to `compact()` as I wrote above, but this really merits a completely separate question. – user207421 Apr 27 '16 at 11:03
  • I already created a new question. I also updated my code based on what you advised but I still get an incomplete file. here is the link http://stackoverflow.com/questions/36888298/incomplete-file-copy-java-nio – jnapor Apr 27 '16 at 11:23