Search code examples
javanio

Java NIO Server


Currently I'm working on a Java NIO Server (single-threaded) and have encountered some problems. The server accepts incoming connections, writes initial packets (the packet contains some data that client uses for further communication) to clients but doesn't read from them. The server tries to read only when I close the client and, of course, it returns -1.

When accepting connection, it's being registered under:

selectionKey = socketChannel.register(_selector, SelectionKey.OP_READ)

selectionKey.isReadable() returns false (should it?)

Before sending initial packet, ops are changed to:

_selectionKey.interestOps(_selectionKey.interestOps() | SelectionKey.OP_WRITE)

After sending initial packet, ops are changed to:

selectedKey.interestOps(selectedKey.interestOps() & ~SelectionKey.OP_WRITE)

Packet gets sent.

What could be the problem? Can it be related to client?


Solution

  • selectionKey.isReadable() returns false (should it?)

    Certainly, until there is data to read, or end of stream.

    Before sending initial packet, ops are changed to:

    _selectionKey.interestOps(_selectionKey.interestOps() | SelectionKey.OP_WRITE)

    Bad idea. OP_WRITE is almost always ready, i.e. except when the socket send buffer is full, so you will just cause your Selector.select() method to spin mindlessly.

    When you want to write to the channel, just write. Do that in the classic loop:

    while (buffer.position() > 0)
    {
        buffer.flip();
        int count = channel.write(buffer);
        buffer.compact();
        if (count == 0)
        {
            // see below ...
        }
    }
    

    If count is zero, you should then register for OP_WRITE, break out of the loop, and go back to the Selector loop. If you got out of this loop without that happening, deregister OP_WRITE.

    Note that this implies you have a write buffer per channel. For similar reasons (read() returning zero) you also need a read buffer per channel. That in turn implies a channel 'session' object that contains them both, and that is probably the attachment of the channel's selection key.