Search code examples
javanio

Efficient read/write approach with Java NIO


Let's say we have SocketChannel (in non-blocking mode) that registered with Selector for read interest. Let's say after select() Selector tells us that this channel is ready for read and we have some ByteBuffer. We want to read some bytes from our channel to this buffer (ByteBuffer is cleared before reading). For this we use channel's read() method that returns actual number of bytes read. Lets suppose that this number is positive after read from channel and also ByteBuffer's method hasRemaining() returns true. Is it practical in this situation to immediately try to read from same channel some more? The same question for write(). If write() returns positive value and not all contents of the buffer was sent, is it practical to immediately try again until write() returns zero?


Solution

  • If you get a short read result, there is no more data to read without blocking, so you must not read again until there is. Otherwise the next read will almost certainly return zero or -1.

    If the read fills the buffer, it might make sense from the point of view of that one connection to keep reading until it returns <= 0, but you are stealing cycles from the other channels. You need to consider fairness as well. In general you should probably do one read and keep iterating over the selected keys. If there's more data there the select will tell you next time.

    Use big buffers.

    This also means that it's wrong to clear the buffer before each read. You should get the data out with a flip/get/compact cycle, then the buffer is ready to read again and you don't risk losing data. This in turn implies that you need a buffer per connection.