Using a Selector to Manage Non-Blocking Sockets

Although you could poll each non-blocking socket for events, a more convenient and efficient method is to use a selector to manage the channels. The selector efficiently monitors the channels for changes and reports the events through a single method call.

The first step is to register a channel with a selector. The registration process yields an object called a selection key which identifies the selector/socket channel pair (a channel could be registered with another selector for different events). When an event occurs on a channel, the selector returns the selection key for that channel. The selection key also contains the type of event that occurred.

This example creates two sockets and registers them with a selector. The example then uses the selector to listen for events.

See also Using a Selector to Manage Non-Blocking Server Sockets.

// Create a selector and register two socket channels
Selector selector = null;
try {
    // Create the selector
    selector = Selector.open();

    // Create two non-blocking sockets. This method is implemented in
    // Creating a Non-Blocking Socket.
    SocketChannel sChannel1 = createSocketChannel("hostname.com", 80);
    SocketChannel sChannel2 = createSocketChannel("hostname.com", 80);

    // Register the channel with selector, listening for all events
    sChannel1.register(selector, sChannel1.validOps());
    sChannel2.register(selector, sChannel1.validOps());
} catch (IOException e) {
}

// Wait for events
while (true) {
    try {
        // Wait for an event
        selector.select();
    } catch (IOException e) {
        // Handle error with selector
        break;
    }

    // Get list of selection keys with pending events
    Iterator it = selector.selectedKeys().iterator();

    // Process each key at a time
    while (it.hasNext()) {
        // Get the selection key
        SelectionKey selKey = (SelectionKey)it.next();

        // Remove it from the list to indicate that it is being processed
        it.remove();

        try {
            processSelectionKey(selKey);
        } catch (IOException e) {
            // Handle error with channel and unregister
            selKey.cancel();
        }
    }
}

public void processSelectionKey(SelectionKey selKey) throws IOException {
    // Since the ready operations are cumulative,
    // need to check readiness for each operation
    if (selKey.isValid() && selKey.isConnectable()) {
        // Get channel with connection request
        SocketChannel sChannel = (SocketChannel)selKey.channel();

        boolean success = sChannel.finishConnect();
        if (!success) {
            // An error occurred; handle it

            // Unregister the channel with this selector
            selKey.cancel();
        }
    }
    if (selKey.isValid() && selKey.isReadable()) {
        // Get channel with bytes to read
        SocketChannel sChannel = (SocketChannel)selKey.channel();

        // See Reading from a SocketChannel
    }
    if (selKey.isValid() && selKey.isWritable()) {
        // Get channel that's ready for more bytes
        SocketChannel sChannel = (SocketChannel)selKey.channel();

        // See Writing to a SocketChannel
    }
}

Comments

1 Apr 2010 - 2:05pm by Volt (not verified)

Hello,

Thank you for the nicely-written code. It has helped me write my own socket code. A small fix on line 14 of the above example:

sChannel2.register(selector, sChannel1.validOps());
maybe should be changed to
sChannel2.register(selector, sChannel2.validOps());

I know it comes out the same either way.

Thanks again!
Volt

28 Sep 2011 - 5:14am by Flo (not verified)

How does for example a "write-event" look like?
How can I say: "SocketChannel X write this ByteArray[]!" ?

greetings

28 Sep 2011 - 5:15am by Flo (not verified)

How does for example a "write-event" look like?
How can I say: "SocketChannel X write this ByteArray[]!" ?

greetings

28 Jan 2012 - 9:57am by Marty (not verified)

Thanks for introducing a little rationality into this dbetae.

Post a comment

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters shown in the image. Ignore spaces and be careful about upper and lower case.