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…
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
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.
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
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
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”.
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
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.