JavaNIO

Three core components of JavaNIO: channel, buffer, selector.

1. channel:

1.1 primary channel implementions:
  • FileChannel : reads data from and to files.
  • DatagramChannel : read and write data over the network via UDP.
  • SocketChannel : read and write data over the network via TCP.
  • ServerSocketChannel : allows you to listen for incoming TCP connections, like a web server does. For each incoming connection a SocketChannel is created.

1.2 Java NIO Channels are similar to streams with a few differences:
  • You can both read and write to a Channels. Streams are typically one-way (read or write).
  • Channels can be read and written asynchronously.
  • Channels always read to, or write from, a Buffer.

2. buffer:

NIO buffers are used when interacting with NIO channels. As you know, data is read from channerls into buffers, and write from buffers into channels.

2.1 Basic buffer usage:
  • write data into the buffer
  • call buffer.flip()
  • read data out of the buffer
  • call buffer.clear() or buffer.compact()

2.2 Two different mode of buffer:
  • write mode
  • read mode

2.3 Three main properties of buffer:
  • capacity: size of this buffer
  • position:
    • write mode: initially position=0, maximally position=capacity-1, increased while writing into the buffer.
    • In read mode: when you flip a buffer from write mode to read mode, position reset to zero. As you reading from the buffer, position increases.
  • limit
    • write mode: the limit of how much data you can write into the buffer. In write mode the limit=capacity.
    • read mode: the limit of how much data you can read from the data. when flipping a buffer into a read mode, limit=position you has written in write mode.

2.4 Allocate a buffer:
1
2
ByteBuffer bb = ByteBuffer.allocate(100);
CharBuffer cb = CharBuffer.allocate(100);

2.5 Write data into a buffer:
  • write data from a channel into a buffer
  • write data into the buffer by yourself, via buffer.put()

2.6 Swithch buffer from write mode ito read mode:
  • buffer.flip(): set position back to 0, and set limit to position where just was.

2.7 Read data from a buffer:
  • read data from the buffer into a channel
  • read data from the buffer by yourself, via buffer.get()

2.8 buffer.rewind():

set the position back to 0, so you can reread all the data in the buffer.


2.9 buffer.clear() & buffer.compact():

Once you have done reading, you can call buffer.clear() or buffer.compact() to switch into write mode.

  • buffer.clear(): set position=0 and limit=capacity
  • buffer.compact(): copies all unread data to the beginning of the Buffer. Then sets position to right after the last unread element and limit=capacity.

2.10 buffer.mark() and buffer.reset():
  • buffer.mark(): mark a given position
  • buffer.reset(): reset the position back to the marked position

2.11 buffer.equals() and buffer.compareTo():
  • Two buffers are equal if:
    • They are of the same type (byte, char, int etc.)
    • They have the same amount of remaining bytes, chars etc. in the buffer.
    • All remaining bytes, chars etc. are equal.
  • The compareTo() method compares the remaining elements (bytes, chars etc.) of the two buffers

3. selector

A Selector is a Java NIO component which can examine one or more NIO Channels, and determine which channels are ready for e.g. reading or writing.

3.1 Creating a selector:
1
Selector selector = Selector.open();

3.2 Registering channels with the selector:

The Channel must be in non-blocking mode to be used with a Selector. This means that you cannot use FileChannel’s with a Selector.

1
2
3
4
5
//set the channel to non-blocking mode 
channel.configureBlocking(false);

//
SelectionKey key = channel.register(selector,SelectionKey.OP_READ);

Four events you can listen for is:

  • SelectionKey.OP_CONNECT
  • SelectionKey.OP_ACCEPT
  • SelectionKey.OP_READ
  • SelectionKey.OP_WRITE

3.3 SelectionKey:

When register a channel with s selector, the register() method returns a SelectonKey objects. This SelectionKey object contains a few insteresting properties:

  • The interest set
  • The ready set
  • The Channel
  • The Selector
  • An attached object(optional)
Interest Set: is the set of events you are interested in “selecting”. You can read and write that interest set via SelectionKey like this.
1
2
3
4
5
6
int interestSet = selectionKey.interestOps();

boolean isInterestedInAccept = interestSet & SelectionKey.OP_ACCEPT;
boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT;
boolean isInterestedInRead = interestSet & SelectionKey.OP_READ;
boolean isInterestedInWrite = interestSet & SelectionKey.OP_WRITE;
Ready Set: is the set of operations the channel is ready for.

You can access the ready set like this:

1
int readySet = selectionKey.readyOps();

Or test what events /operations the channel is ready for

1
2
3
4
selectionKey.isAcceptable();
selectionKey.isConnectable();
selectionKey.isReadable();
selectionKey.isWritable();

Channel & Selector:
1
2
3
Channel  channel  = selectionKey.channel();

Selector selector = selectionKey.selector();
Attach a object:

You can attach an object to a SelectionKey this is a handy way of recognizing a given channel.

1
2
3
selectionKey.attach(theObject);

Object attachedObj = selectionKey.attachment();

3.4 Selecting Channels via a selector:

Get the channels that are ‘ready’ for the events you are interested in:

  • selector.select(): blocks until at least one channel is ready for the events you registered for.
  • selector.select(long timeout): does the same as select() except it blocks for a maximum of timeout milliseconds.
  • selector.selectNow(): doesn’t block at all. It returns immediately with whatever channels are ready.

Access the ready channels via the ‘selected key set’:

1
Set<SelectionKey> selectedKeys = selector.selectedKeys();

You can iterate this selected key set to access the ready channels.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Set<SelectionKey> selectedKeys = selector.selectedKeys();

Iterator<SelectionKey> keyIterator = selectedKeys.iterator();

while(keyIterator.hasNext()) {

SelectionKey key = keyIterator.next();

if(key.isAcceptable()) {
// a connection was accepted by a ServerSocketChannel.


} else if (key.isConnectable()) {
// a connection was established with a remote server.


} else if (key.isReadable()) {
// a channel is ready for reading


} else if (key.isWritable()) {
// a channel is ready for writing

}

keyIterator.remove();

}

3.5 selector.wakeUp():

A thread that has called the select() method which is blocked, can be made to leave the select() method, even if no channels are yet ready. This is done by having a different thread call the Selector.wakeup() method on the Selector which the first thread has called select() on.

3.6 selector.close():

Close the Selector and invalidates all SelectionKey instances registered with this Selector. The channels themselves are not closed.

3.7 Selector example:
1
2