A lot of people who have just come in contact with NIO have the first glimpse of a relatively obscure Java API, such as Channel,selector,socket or something; and then there's a bunch of hundreds of lines of code to demonstrate the service-side demo of NiO, so here's a user-friendly introduction.
NiO we generally think of as new I/O (also the official term), because it's new than the old I/O class library (which is already introduced in JDK 1.4), this term will continue to take a long time, even if they are already "old" in the present, so it prompts us to name the Need to think about it) and make a big difference. But the folk and many people call it non-block I/O, that is, non-blocking I/O, because so called, more can reflect its characteristics. The following NIO, however, does not refer to the entire new I/O library, but to non-blocking I/O.
NIO provides two different socket channel implementations for Socketchannel and Serversocketchannel corresponding to sockets and serversocket in the traditional bio model.
There are two new channels that support both blocking and non-blocking modes. Blocking mode usage is as simple as traditional support, but not good for performance and reliability; The non-blocking mode is just the opposite.
For low load, low concurrency applications, you can use synchronous blocking I/O to increase the development rate and maintain better maintenance; For high load, high concurrency (network) applications, use NIO's non-blocking mode for development. Java NIO Foundation implementation
Buffer buffers
Buffer is an object that contains some data to write to or read out.
In a NIO library, all data is processed in a buffer. When reading data, it is read directly into the buffer, and is written to the buffer when the data is written. Any time you access data in NiO, you are operating through a buffer.
The buffer is actually an array and provides information on data structure access and the maintenance of read and write locations.
Specific buffers have these: Bytebuffe, Charbuffer, Shortbuffer, Intbuffer, Longbuffer, Floatbuffer, DoubleBuffer. They implemented the same interface: Buffer.
Channel Channel
We read and write data through channel, it's like a pipe, it's a channel. The channel is different from the flow where the channel is bidirectional and can be used for reading, writing, and simultaneous read and write operations.
The underlying operating system's channels are generally full-duplex, so Full-duplex channel can better map the underlying operating system APIs than streaming.
Channel mainly divided into two major categories: Selectablechannel: User Network Read-write FileChannel: for file operations
The Serversocketchannel and socketchannel that the following code will cover are Selectablechannel subclasses.
Multiplex Multiplexer Selector
Selector is the foundation of Java NIO programming.
Selector provides the ability to choose a task that is already in place: Selector will constantly poll the channel that is registered on it, and if a read or write event occurs on a channel, the channel is in a ready state and will be polled by selector. The Selectionkey can then be used to obtain a set of ready channel for subsequent I/O operations.
A selector can poll multiple channel at the same time, only one thread is responsible for selector polling and can access thousands of clients. NiO Use
Recall the Bio model, the reason for the need for multiple threads, because in the I/O operation, there is no way to know whether to write, can read, only "silly", even through various estimates, the operating system has not been able to read and write, also can not be in the Socket.read () and the Socket.write () function, the two functions cannot be effectively interrupted. So in addition to more than a short process, there is no good way to use the CPU.
The read-write function of NiO can be returned immediately, which gives us the best chance to use the CPU without a thread: If a connection cannot read or write (Socket.read () returns 0 or socket.write () returns 0), we can write it down. The method of recording is usually to register the mark bit on the selector and then switch to the other Ready Connection (channel) to continue reading and writing.
Think about what's going on in the socket network communication: We need to receive a client connection on the server side, there's a "Accept" event, and a "read" event when the client connects to the server and the connection has a "Connect" event for each read operation. There is a "write" event for each write operation
And above we say that the connection is abstracted for channel, then we can register the channels and events on the multiplexer selector. On the server side: Serversocketchannel.register (Selector, selectionkey.op_accept);
Registering Serversocketchannel in selector and binding selectionkey.op_accept events; calling Multiplexer Selector.select (); If the channel has already occurred to receive the client's event, then it can be select by multiplexer, then obtain the socket connected to the client, and register the Read and write event of the socket to the selector . It is also possible for the client to register other events with the selector, and then the event can be triggered by the Select () function to find the last program to continue polling selector, according to the different event types select to call the corresponding handler processing.
The Select () function calls the underlying function of the system, and after Linux 2.6 is a SELECT, poll,2.6 is Epoll,windows is IOCP.
Pseudo code is as follows:
interface channelhandler{void channelreadable (Channel Channel);
void Channelwritable (Channel Channel);
class channel{socket socket;
Event event;//Read, write, or connect}//io thread main loop: Class Iothread extends thread{public void run () {Channel Channel;
The selected event and the corresponding connection while (Channel=selector.select ()) {if (channel.event==accept) {//triggered the Accept event is a new connection.
We need to register for this new connection read and write event Registernewchannelhandler (channel);
if (channel.event==write) {//If it can be written, write event Getchannelhandler (channel). Channelwritable (channel);
if (channel.event==read) {//If it can be read, perform read event Getchannelhandler (channel). Channelreadable (channel);
}}///all Channel corresponding event processor map<channel,channelhandler> Handlermap; }
Note that the select is blocked, whether through an operating system notification (EPOLL) or constant polling (Select,poll), which is blocked. So you can confidently call this function in a while (true) without worrying about the CPU idling. We can also call Selector.select (1000) (select once per second) by setting the cycle.
Selector contains a set of Selectionkey, recording the various channel and their interested events, please click on the details:
http://blog.csdn.net/u010412719/article/details/52863704
Reference to the U.S. group reviews technical Team article: Https://tech.meituan.com/nio.html
(No, I summed up the good ah hahaha so read my blog on the line)
complete code to implement NIO in the final comparison of NiO with bio
All system I/O is divided into two phases: waiting for ready and operating. For example, a reading function is divided into a waiting system readable and true to read; Similarly, write functions are divided into waiting cards to be written and true to write.
It should be explained that the wait-ready blocking is not CPU-bound, is in "Empty Wait", while the real read-write operation blocking is to use CPU, really in the "work", and this process is very fast, belongs to memory copy, bandwidth is usually above 1gb/s level, can be understood as basically not time-consuming.
The following illustration is a comparison of several common I/O models:
Java NiO is the second or third form: The second: In a while loop inside constantly check Selector whether there are events triggered Selector.select (1000) The third: Selector.select () Checks whether there is a ready event, and if not, it blocks until the Ready event function returns. reactor
There is an article very well written: http://www.blogjava.net/DLevin/archive/2015/09/02/427045.html
You can have a look, I'll emphasize the point here.
Graphic:
1. Handle: In network programming, this is generally referred to as a socket Handle, a network connection (Connection, channel in Java NIO). This channel is registered in synchronous event demultiplexer to listen for events that occur in handle, and for Serversocketchannnel can be connect events, The Socketchannel can be read, WRITE, close events, and so on.
2. Synchronous Event Demultiplexer: multiplexer, blocking the arrival of events waiting in a series of handle, and if blocking waits to return, represents the type of event returned that can be performed without blocking in the returned handle. This module is typically implemented using the operating system's select. Encapsulated in Java NiO with selector, when Selector.select () is returned, the selector Selectedkeys () method can be invoked to fetch the set. A Selectionkey expresses a channel that has an event and the type of event on that channel.
3. The main module of the initiation Dispatcher:reactor mode, Event Scheduler, commonly referred to as reactor, is used to manage event Handler, the EventHandler container, for registering, removing EventHandler, and so on; In addition, it also acts as an entry call to the reactor mode, in which the Select method of synchronous event Demultiplexer is invoked to block the wait event return, and when blocking waits to return, The Handle_event () method in the callback EventHandler is distributed to the corresponding event handler processing according to the handle of the event.
4. Define the event-handling method: Handle_event () for use by the Initiationdispatcher callback.
Note that in Java NIO we registered a connection-related "Accept" "Connect" event, and then read and write to register the read and write events to Multiplexer, and the next read and write event will be select. This is the legendary multiplex IO.
In addition reactor is translated as "reaction", the origin of "reaction" in the name:
"Reaction" is "inverted", "control reversal"
Instead of invoking the reactor, the specific event handler assigns a specific event handler to a specific event handler that responds to the occurrence of a specified event; This control reversal is called the "Hollywood Rule" (Don't call me, let me call you) NIO implementation code
One, server-side code
public class Server {
private static synchronized void start (int port) {
Serverhandle serverhandle = new Serverhand Le (port);
New Thread (Serverhandle, "Server"). Start ();
}
public static void Main (string[] args) {
start (12345);
}
}
Server Processing class Serverhandle:
Class Serverhandle implements Runnable {private Selector m_selector;
Private Serversocketchannel M_serverchannel;
Private volatile Boolean m_started;
Public serverhandle (int vport) {try {m_selector = Selector.open ();
Server Listening channel Serversocketchannel Tserverchannel = Serversocketchannel.open ();
If true, this channel will be placed in blocking mode, and if False, the channel will be placed in non-blocking mode tserverchannel.configureblocking (FALSE);
Tserverchannel.bind (New Inetsocketaddress (Vport), 1024);
Register server channel to Selector, monitor ACCEPT event Tserverchannel.register (M_selector, selectionkey.op_accept);
M_started = true;
SYSTEM.OUT.PRINTLN ("Server started, port number:" + vport);
catch (IOException e) {e.printstacktrace ();
The public void Stop () {m_started = false; @Override public void Run () {while (m_started) {try {//) regardless of whether a read-write event occurs, Selec TOr is awakened once after 1s m_selector.select (1000);
Or in the following way://will block until the Selector inside the Ready event//m_selector.select ();
set<selectionkey> Tkeys = M_selector.selectedkeys ();
iterator<selectionkey> titerator = Tkeys.iterator ();
Selectionkey TKey;
Polling while (Titerator.hasnext ()) {TKey = Titerator.next ();
Titerator.remove ();
try {handleinput (TKey);
The catch (IOException e) {if (null!= tKey) {tkey.cancel ();
if (null = = Tkey.channel ()) {Tkey.channel (). Close ();
catch (IOException e) {
E.printstacktrace ();
} ///Close Selector will automatically close the resource if (null!= m_selector) {try {
M_selector.close ();
catch (IOException e) {e.printstacktrace ();
}} private void Handleinput (Selectionkey vkey) throws IOException {if (Vkey.isvalid ()) { if (vkey.isacceptable ()) {Serversocketchannel Tserverchannel = (serversocketchannel) vkey.channel
();
Socketchannel Tsocketchannel = tserverchannel.accept ();
Tsocketchannel.configureblocking (FALSE);
Get new Connection Register read event Tsocketchannel.register (M_selector, Selectionkey.op_read); ///Read message if (Vkey.isreadable ()) {Socketchannel Tsocketchannel = (socketchannel) vkey
. Channel ();
Must use the buffer bytebuffer Tbuffer = bytebuffer.allocate (1024); int treadbytes = Tsocketchannel.read (tBuFfer);
if (0 < treadbytes) {tbuffer.flip ();
byte[] tbytes = new byte[tbuffer.remaining ()];
Tbuffer.get (tbytes);
String texpression = new String (tbytes, "UTF-8");
SYSTEM.OUT.PRINTLN ("Server received message:" + texpression);
String TResult = "This sentence is sent over by the server";
Dowrite (Tsocketchannel, TResult);
//Read no message shutdown resource else if (0 > Treadbytes) {//Even if key was cancel his channel is still there.
Vkey.cancel ();
Tsocketchannel.close ();
}}//Send data private void Dowrite (Socketchannel vchannel, String vresponse) throws IOException {
byte[] Tbytes = vresponse.getbytes ("UTF-8");
Bytebuffer Twritebuffer = bytebuffer.allocate (tbytes.length);
Twritebuffer.put (tbytes);
Twritebuffer.flip ();
Vchannel.write (Twritebuffer);
}
}
Second, the client code:
public class Client {
private static String Default_host = "127.0.0.1";
private static int default_port = 12345;
private static Clienthandle Clienthandle;
public static void Start () {
start (default_host,default_port);
}
public static synchronized void start (String ip,int port) {
if (null!= clienthandle) clienthandle.stop ();
Clienthandle = new Clienthandle (ip,port);
New Thread (Clienthandle, "Server"). Start ();
}
Send messages to the server public
static Boolean sendmsg (String msg) throws exception{
clienthandle.sendmsg (msg);
return true;
}
public static void Main (string[] args) throws Exception {
start ();
while (Client.sendmsg new Scanner (system.in). nextline ());
}
Client Processing class Serverhandle:
Class Clienthandle implements Runnable {private String m_host;
private int m_port;
Private Selector M_selector;
Private Socketchannel M_socketchannel;
Private volatile Boolean m_started;
Clienthandle (String vip, int vport) {m_host = VIP;
M_port = Vport;
try {m_selector = Selector.open ();
M_socketchannel = Socketchannel.open ();
M_socketchannel.configureblocking (FALSE);
M_started = true;
catch (IOException e) {e.printstacktrace ();
} void Stop () {m_started = false;
@Override public void Run () {try {doconnect ();
catch (IOException e) {System.out.println ("Client connection failed");
while (m_started) {try {m_selector.select (1000);
set<selectionkey> Tkeys = M_selector.selectedkeys (); Iterator<selectionkey> TITerator = Tkeys.iterator ();
Selectionkey TKey;
while (Titerator.hasnext ()) {TKey = Titerator.next ();
Titerator.remove ();
try {handleinput (TKey);
The catch (IOException e) {if (null!= tKey) {tkey.cancel ();
if (null!= tkey.channel ()) {Tkey.channel (). Close ();
catch (IOException e) {
E.printstacktrace (); }//Close Selector will close all resources in it if (null!= m_selector) {try {M_selecto
R.close ();
catch (IOException e) {e.printstacktrace (); }} private void Handleinput (Selectionkey vkey) throws IOException{if (Vkey.isvalid ()) {Socketchannel Socketchannel = (socketchannel) vkey.channel (); If it is a connection event if (vkey.isconnectable ()) {if (Socketchannel.finishconnect ()) S
YSTEM.OUT.PRINTLN ("Client connected to server side");
else System.exit (1); //Read Message if (Vkey.isreadable ()) {//Create Bytebuffer, and open a 1M buffer Bytebu
Ffer buffer = bytebuffer.allocate (1024);
Reads the request code stream, returns the number of bytes read int readbytes = socketchannel.read (buffer);
Read to Byte, codec for bytes if (0 < Readbytes) {//Set the current limit of the buffer to position=0 for subsequent read operations on the buffer
Buffer.flip ();
Creates an array of bytes based on the number of readable bytes in the buffer byte[] bytes = new byte[buffer.remaining ()];
Copies a buffer-readable byte array into the newly created array buffer.get (bytes);
string result = new String (bytes, "UTF-8"); SYSTEM.OUT.PRINTLN ("Client received message:" + result);
//Link has been closed, releasing resource else if (0 > Readbytes) {vkey.cancel ();
Socketchannel.close ();
}}} private void Dowrite (Socketchannel channel, String request) throws IOException {
Encodes the message as a byte array byte[] bytes = Request.getbytes ();
Creates bytebuffer bytebuffer WriteBuffer = bytebuffer.allocate (bytes.length) based on array capacity;
Copies the byte array to the buffer Writebuffer.put (bytes);
Flip Operation Writebuffer.flip ();
The byte array of the Send buffer Channel.write (writebuffer); The private void Doconnect () throws IOException {//client request connects to the server and registers the connection event M_socketchannel.connect (new Ine
Tsocketaddress (M_host, M_port));
M_socketchannel.register (M_selector, selectionkey.op_connect);
} void Sendmsg (String msg) throws Exception {//data sent to register read event M_socketchannel.register (M_selector, Selectionkey.op_read);
Dowrite (M_socketchannel, msg);
}
}