Java NIO offers SocketChannel and ServerSocketChannel which can be set to non-blocking mode (asynchronous). Most of the operations return a value that corresponds to success or that the operation is not yet done. What is the purpose of AynchronousSocketChannel and AsynchronousServerSocketChannel then, apart from the callback functionalities?
which can be set to non-blocking mode (asynchronous)
There's your misapprehension, right there. Non-blocking mode is different from asynchronous mode.
A non-blocking operation either transfers data or it doesn't. In either case there is no blocking, and the operation is complete once it returns. This mode is supported by SocketChannel, DatagramSocketChannel, and Selector.
An asynchronous operation starts when you call the method and continues in the background, with the result becoming available at a later time via a callback or a Future. This mode is supported by the AsynchronousSocketChannel etc classes you mention in your question.
The AynchronousSocketChannel and AsynchronousServerSocketChannel come into their own when using the methods that take a CompletionHandler.
For example the code in a server might look like this:
asynchronousServerSocketChannel.accept(Void, new ConnectionHander());
Where ConnectionHander is an implementation of CompletionHandler that deals with client connections.
The thread that makes the accept call can then continue doing other work and the NIO API will deal with scheduling the callback to the CompletionHandler when a client connection is made (I believe this is an OS level interupt).
The alternative code might look like this:
SocketChannel socketChannel = serverSocketChannel.accept();
Depending on the mode, the calling thread is now blocked until a client connection is made or null is returned leaving you to poll. In both cases, it's you that has to deal with the threads, which generally means more work.
At the end of the day, you take your pick based on your particular use-case, though I've generally the former produces clearer more reliable code.
Related
I'm experimenting with some network code, and I'm trying to figure out a good way to trigger writes to my DatagramChannel after having processed an event on a separate thread. This is quite simple for TCP, since you have a separate socket on which you can register your write interest (see reactor pattern, etc). For UDP, however, registering and deregistering interest with the datagram channel doesn't work so well, since I'm basically just modifying the same selection key.
I feel like you either block on the send in the event handler thread (wrong because then we're using blocking sends), or you block on a queue or something to take the responses and write them (also wrong because then we're blocking the selector thread).
I'd like to do something like switch the interest to write once I have something to write, and then back again to read, but then I run the risk of a race where I set it back to read after a write has been queued up, and then that write waits until I get the next read, which is also bad.
Yes, I know that there are other, potentially better suited threading models for these sorts of things, but I'm experimenting, so I'm curious. =)
You don't have to set the interest-ops to write when you want to write. Just write, from whatever thread you happen to be in. Only if that write returns zero do you need to worry about write interest-ops, as per many answers here.
i'm reading the TCP/IP Socket in Java, about the serversocket, it says
When we call accept() on that ServerSocket
instance, if a new connection is pending, accept() returns immediately; otherwise it blocks
until either a connection comes in or the timer expires, whichever comes first. This allows
a single thread to handle multiple connections. Unfortunately, the approach requires that
we constantly poll all sources of I/O, and that kind of “busy waiting” approach again introduces
a lot of overhead from cycling through connections just to find out that they have
nothing to do.
As I understand it, should this be "notified" when a connection comes thus should not be "busy waiting"? Did i misunderstand something...?
-----------------EDIT----------------------
The whole paragraph is as below:
Because of these complications, some programmers prefer to stick with a single-threaded
approach, in which the server has only one thread, which deals with all clients—not sequentially,
but all at once. Such a server cannot afford to block on an I/O operation with any
one client, and must use nonblocking I/O exclusively. Recall that with nonblocking I/O, we specify the maximum amount of time that a call to an I/O method may block (including zero).
We saw an example of this in Chapter 4, where we set a timeout on the accept operation
(via the setSoTimeout() method of ServerSocket). When we call accept() on that ServerSocket
instance, if a new connection is pending, accept() returns immediately; otherwise it blocks
until either a connection comes in or the timer expires, whichever comes first. This allows
a single thread to handle multiple connections. Unfortunately, the approach requires that
we constantly poll all sources of I/O, and that kind of “busy waiting” approach again introduces
a lot of overhead from cycling through connections just to find out that they have
nothing to do
It's mostly nonsense, even in the entire quotation. Either you are using blocking I/O, in which case you need a thread per connection, and another per accept() loop, or you are using non-blocking I/O, in which case you have select(), or, from Java 7, you are using Asynchronous I/O, in which case it is all callbacks into completion handlers. In none of these cases do you need to poll or busy-wait.
I think he must be referring to using blocking mode with very short timeouts, but it's really most unclear.
I am trying to understand SocketChannels, and NIO in general. I know how to work with regular sockets and how to make a simple thread-per-client server (using the regular blocking sockets).
So my questions:
What is a SocketChannel?
What is the extra I get when working with a SocketChannel instead of a Socket.
What is the relationship between a channel and a buffer?
What is a selector?
The first sentance in the documentation is A selectable channel for stream-oriented connecting sockets.. What does that mean?
I have read the also this documentation, but somehow I am not getting it...
A Socket is a blocking input/output device. It makes the Thread that is using it to block on reads and potentially also block on writes if the underlying buffer is full. Therefore, you have to create a bunch of different threads if your server has a bunch of open Sockets.
A SocketChannel is a non-blocking way to read from sockets, so that you can have one thread communicate with a bunch of open connections at once. This works by adding a bunch of SocketChannels to a Selector, then looping on the selector's select() method, which can notify you if sockets have been accepted, received data, or closed. This allows you to communicate with multiple clients in one thread and not have the overhead of multiple threads and synchronization.
Buffers are another feature of NIO that allows you to access the underlying data from reads and writes to avoid the overhead of copying data into new arrays.
By now NIO is so old that few remember what Java was like before 1.4, which is what you need to know in order to understand the "why" of NIO.
In a nutshell, up to Java 1.3, all I/O was of the blocking type. And worse, there was no analog of the select() system call to multiplex I/O. As a result, a server implemented in Java had no choice but to employ a "one-thread-per-connection" service strategy.
The basic point of NIO, introduced in Java 1.4, was to make the functionality of traditional UNIX-style multiplexed non-blocking I/O available in Java. If you understand how to program with select() or poll() to detect I/O readiness on a set of file descriptors (sockets, usually), then you will find the services you need for that in NIO: you will use SocketChannels for non-blocking I/O endpoints, and Selectors for fdsets or pollfd arrays. Servers with threadpools, or with threads handling more than one connection each, now become possible. That's the "extra".
A Buffer is the kind of byte array you need for non-blocking socket I/O, especially on the output/write side. If only part of a buffer can be written immediately, with blocking I/O your thread will simply block until the entirety can be written. With non-blocking I/O, your thread gets a return value of how much was written, leaving it up to you to handle the left-over for the next round. A Buffer takes care of such mechanical details by explicitly implementing a producer/consumer pattern for filling and draining, it being understood that your threads and the JVM's kernel will not be in sync.
Even though you are using SocketChannels, It's necessary to employ thread pool to process channels.
Thinking about the scenairo you use only one thread which is responsible for both polling select() and processing the SocketChannels selected from Selectors, if one channel takes 1 seconds for processing, and there are 10 channels in queue, it means you have to wait 10 seconds before next polling which is untolerable. so there should be a thread pool for channels processing.
In this sense, i don't see tremendous difference to the thread-per-client blocking sockets pattern. the major difference is in NIO pattern, the task is smaller, it's more like thread-per-task, and tasks could be read, write, biz process etc. for more detail, you can take a look at Netty's implementation of NioServerSocketChannelFactory, which is using one Boss thread accepting connection, and dispatch tasks to a pool of Worker threads for processing
If you are really fancy at one thread, the bottom-line is at least you shold have pooled I/O threads, because I/O operations is often oders of magnitude slower than instruction-processing cycles, you would not want the precious one thread being blocked by I/O, and this is exactly NodeJS doing, using one thread accept connection, and all I/O are asynchornous and being parallelly processed by back-end I/O threads pool
is the old style thread-per-client dead?
I don't think so, NIO programming is complex, and multi-threads is not naturally evil, Keep in mind that modern operating systems and CPU's become better and better at multitasking, so the overheads of multithreading becomes smaller over time.
I am planning to use java NIO for my project, but one of my requirement is to keep the requests configurable, i.e. the client can select the request to be: 1. blocking, 2. non blocking.
So, is it possible to use NIO in a sync. way?
There is an option on the client code when creating the channel:
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(true);
But, I get this error when I make it as true.
This is the client code I am using from this tutorial.
java.nio.channels.IllegalBlockingModeException
at java.nio.channels.spi.AbstractSelectableChannel.register(AbstractSelectableChannel.java:172)
at java.nio.channels.SelectableChannel.register(SelectableChannel.java:254)
at com.dds.client.DDSClient.run(DDSClient.java:77)
at java.lang.Thread.run(Thread.java:680)
The javadocs for register(...) state that if you call the method on a channel that is in blocking mode, that exception will be thrown. A selector can only handle a non-blocking channel.
You need to change your code to use a blocking operations (e.g. read or write) rather than register and select when you want blocking semantics.
You can't use select() on a blocking channel, as the Javadocs say. You more or less have to use the model of a thread per channel.
What is the reason for this strange requirement?
Using non-blocking I/O, the code for connecting to a remote address looks something like:
SocketChannel channel = SelectorProvider.provider().openSocketChannel();
channel.configureBlocking(false);
channel.connect(address);
The connection process will then have to be finished by invoking finishConnect() on the channel when some selector says the corresponding key isConnectable().
Is there a way to specify the connection timeout when using this idiom?
Interesting question. I'm not sure that nio itself provides a solution.
In my experience, I've run a Callable to attempt the connection, and then used the Future to poll for a response, using 'interval' and 'timeout' variables to loop and Thread.sleep() for a response.
Hopefully that points you in a useful direction ...
Also, I suggest you take a look at Apache Mina (you could describe Mina as an nio framework). It handles a lot of this kind of stuff for you, for example in the StreamIoHandler http://mina.apache.org/report/trunk/apidocs/org/apache/mina/handler/stream/StreamIoHandler.html
The question doesn't really make sense. Timeouts are for blocking mode. If you want that, leave the channel in blocking mode and call channel.socket().connect(address, timeout);. If you want non-blocking mode, use your current code; then create a Selector; register the channel for OP_CONNECT; when you get it call finishConnect(), and if that returns true deregister OP_CONNECT and continue with the rest of your code.