tags:

views:

454

answers:

2

Instead of using a selector in the usual way, where for each ready channel a message can be determined and sent, I'd like to choose whichever connection is currently ready and send a message there.

Presumably this can be done by throwing all the channels into a selector for reading and marking them ready for reading if they come out, then doing the same for writing, and then choosing from among those that I've marked ready.

Is this a good idea, is there a better way to do this, and what should I watch out for? For example, the Rox Tutorial states "If you try to mix OP READ and OP WRITE you'll quickly get yourself into trouble. The Sun Windows implementation has been seen to deadlock if you do this." Are there similar gotchas here? What is the best way to implement:

boolean isReadyForRead(SocketChannel c);
boolean isReadyForWrite(SocketChannel c);
+1  A: 

You should be using your SelectionKey's to verify if a socket is ready for read or write, when the selector wakes up.

Here's a very useful tutorial on writing an NIO Server and Client http://rox-xmlrpc.sourceforge.net/niotut/

Malaxeur
I'd like to know when a specific channel is ready, and channels do not have a .isReadyForRead() method. Als, by "wakes up" do you mean "when .select() returns", or are you talking about a threading strategy?
mk
+1 for the pointer to the tutorial
Mark
It's when .select() returns. This is caused by a connection requiring a read or write, or if selector.select() is called. You should then iterate through the selected keys and verify if the selector is ready for read or write. (There are a few other steps but they are all outlined in the tutorial).
Malaxeur
+1  A: 

How about something like this?

public static boolean isReadyForRead(SocketChannel socket) throws IOException {
 return isReady(socket, SelectionKey.OP_READ);
}

public static boolean isReadyForWrite(SocketChannel socket) throws IOException {
 return isReady(socket, SelectionKey.OP_WRITE);
}

public static boolean isReady(SocketChannel socket, int op) throws IOException {
 // Setup
 if (socket.isBlocking()) 
  throw new IllegalArgumentException("Socket must be in non-blocking mode");

 Selector selector = SelectorProvider.provider().openSelector();
    socket.register(selector, op);

    // Real work
    if (selector.selectNow() == 0)
     return false;
    // Just in case selector has other keys
    return selector.selectedKeys().contains(socket.keyFor(selector));
}

This call is terribly inefficient because it does the setup every time. If you have an enclosing class, this should be moved out. If you know selector only contains one key, last line can be changed into "return true;".

I am just doing this for fun. I can't think of a scenario that this will be useful. Select() is designed to tell you the status of sockets efficiently and everyone should use that directly.

ZZ Coder
Are there any problems with doing it this way, though with this moved out? (I've restored the original version of my question.)
mk
I am not familiar with the problem mentioned in the tutorial but we are not doing that. We don't mix READ/WRITE. THe keyset will not be updated for each call so no threading issue.
ZZ Coder