Shane Spoor
Shane Spoor

Reputation: 433

SelectionKey.isAcceptable() Returns "true" When No Incoming Connections

I'm writing a chat server in Java using Java NIO. The server accepts a connection without issue, but any time that select() returns > 0 after the first client, the server socket is always in the selected key-set even if there are no pending connections. Even if select() returns 1, the selected key-set will have 2 elements and include the server socket. This causes accept() to return null.

Any help would be greatly appreciated.

The main loop:

public void start() throws IOException {
    Set<SelectionKey>       keys;
    Iterator<SelectionKey>  keyIterator;
    this.keepGoing = true;

    while (keepGoing) {
        int readyChannels = this.selector.select();

        if (readyChannels == 0) 
        {
            continue;
        }

        keys        = this.selector.selectedKeys();
        keyIterator = keys.iterator();

        while (keyIterator.hasNext())
        {
            SelectionKey currentKey = keyIterator.next();

            if (currentKey.isAcceptable())
            {
                addClient(currentKey);
            }
            if (currentKey.isReadable())
            {
                readSock(currentKey);
            }
            if (currentKey.isWritable())
            {
                // write data to the buffer and remove OP_WRITE
            }
        }
    }

}

The server initialisation code:

public Server(int port) {

    this.listenPort = port;

    try
    {
        this.selector = Selector.open();
        this.listenChannel = ServerSocketChannel.open();
        this.listenChannel.socket().bind(new InetSocketAddress(this.listenPort), BACKLOG);
        this.listenChannel.configureBlocking(false);
        this.listenChannel.register(this.selector, SelectionKey.OP_ACCEPT);
    } 
    catch (IOException e)
    {
        System.out.println("Server could not initialise: " + e.getMessage());
    }

    this.users = new HashMap<>();
}

The addClient method:

private void addClient(SelectionKey key) throws IOException {
    ServerSocketChannel acceptSocket    = (ServerSocketChannel) key.channel();
    SocketChannel       newClient       = acceptSocket.accept();
    SelectionKey        clientKey;

    // Set the new client to non-blocking mode and add to the selector
    newClient.configureBlocking(false);
    clientKey = newClient.register(this.selector, SelectionKey.OP_READ);

    // Add a new key-user pair to the user list
    this.users.put(clientKey, new User());

    // Attach a buffer for reading the packets
    clientKey.attach(new PacketBuffer(newClient));
}

Upvotes: 1

Views: 1104

Answers (1)

user207421
user207421

Reputation: 311023

You must call keyIterator.remove() after keyIterator.next(), or clear the selected key set at the end of the loop. The Selector doesn't remove keys from that set, it's up to you. But you also need to be aware that accept() can return null in non-blocking mode, and program defensively accordingly.

Upvotes: 4

Related Questions