I can't get how NIO works under the hood. Here is a sample code:
// Create the server socket channel
ServerSocketChannel server = ServerSocketChannel.open();
// nonblocking I/O
server.configureBlocking(false);
// host-port 8000
server.socket().bind(new java.net.InetSocketAddress(host,8000));
// Create the selector
Selector selector = Selector.open();
// Recording server to selector (type OP_ACCEPT)
server.register(selector,SelectionKey.OP_ACCEPT);
while (true) {
selector.select(); // blocking operation
Iterator it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey selKey = (SelectionKey) it.next();
// THE MOST INTRIGUING PART HERE!!!
if (selKey.isAcceptable()) {
ServerSocketChannel ssChannel = (ServerSocketChannel) selKey.channel();
SocketChannel sc = ssChannel.accept();
}
it.remove();
}
}
Here I have a couple of questions:
In http://www.developer.com/java/article.php/10922_3837316_2/Non-Blocking-IO-Made-Possible-in-Java.htm they even suggest to accept channel in new thread. I guess it is possible that the following situation may occur.
key1 someClient1 acceptable
key2 someClient2 not acceptable
key3 someClient3 acceptable
startThread1
startThread3
scheduler decides to give time to thread3 instead of thread1
thread3 -> socket.accept() <- actually accepts client1
thread1 -> socket.accept() <- actually accepts client3
So, could you please explain how selector works in pair with ServerSocketChannel and accept method? Because I don't understand in which order #accept accepts clients and how this order related to selectedKeys.
Can I simply do the following:
int availableClients = 0;
while (it.hasNext()) {
SelectionKey selKey = (SelectionKey) it.next();
if (selKey.isAcceptable()) {
++availableClients;
}
it.remove();
}
for (int i = 0; i < availableClients; ++i) {
SocketChannel sc = server.accept();
doSomething(sc);
}
selKey.channel() return a ServerSocketChannel is it exactly the same channel we created in the beginning with ServerSocketChannel.open()?
Yes.
More important question: in most other tutorials selKey.channel(); step is skipped and they simply use SocketChannel client = server.accept(); For example here: http://www.onjava.com/pub/a/onjava/2002/09/04/nio.html?page=2 and here: http://www.developer.com/java/article.php/10922_3837316_2/Non-Blocking-IO-Made-Possible-in-Java.htm So, how does server.accept() knows about current key we process?
It doesn't. They're assuming that there is only one ServerSocketChannel
. Your way is better: it's more general.
In http://www.developer.com/java/article.php/10922_3837316_2/Non-Blocking-IO-Made-Possible-in-Java.htm they even suggest to accept channel in new thread.
I have no idea why. It's a non-blocking call. It will return immediately. The suggestion is pointless. Ignore it. It's a very poor quality tutorial from six years ago, but there were better ones in existence thirteen years ago. Try the Oracle tutorial. The author of this one doesn't seem to understand the point of non-blocking mode at all. The suggestion to use a separate thread for every event is completely and utterly ludicrous. He also doesn't understand how to use OP_WRITE. He makes a false assertion about cancel()
. I could go on. It's doubtful that he has ever executed this code: he certainly didn't investigate its behaviour in any way. How to write a non-scalable NIO server. Quite a feat.
I guess it is possible that the following situation may occur.
I don't even seen why you would be accepting in two threads at the same time, let alone how it could possibly matter to either thread which client it accepts. This is a difficulty invented where none exists.
So, could you please explain how selector works in pair with ServerSocketChannel and accept method? Because I don't understand in which order #accept accepts clients and how this order related to selectedKeys.
The accept()
method returns the next socket in the backlog queue, and OP_ACCEPT fires whenever the backlog queue is non-empty. It's perfectly simple, no mystery. The order doesn't 'relate to selected keys' at all. The selected key is that of the ServerSocketChannel
.
EDIT: It appears you have a major misunderstanding. Consider:
ServerSocketChannel
for OP_ACCEPT
.SelectionKey
in existence, and therefore exactly one in the selected-keys set: that of the ServerSocketChannel
.isAcceptable()
case on that key; accept one or both connections; register those channels for OP_READ.
OK?
Can I simply do the following:
Certainly, but why? There is no advantage to be had by making something complicated out of something simple. Do it the first way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With