One, blocking and non-blocking
Traditional IO streams are blocked. That is, when a thread calls read () or write (), the thread is blocked until some data is read or written, and the thread cannot perform other tasks during this time. As a result, the server side must provide a separate thread for each client to handle when it completes the IO operation of network traffic, and when the server side needs to process a large number of clients, the performance drops dramatically.
Java NIO is non-blocking mode. When a thread reads and writes data from a channel, the thread can perform other tasks if no data is available. Threads typically use the idle time of non-blocking IO to perform IO operations on other channels, so separate threads can manage multiple input and output channels. Therefore, NIO allows the server to use one or a limited number of threads to process all clients connected to the server side at the same time.
Let me take a look at an example of using NIO to demonstrate a blocking style, i.e. without a selector:
Import Java.io.ioexception;import Java.net.inetsocketaddress;import Java.nio.bytebuffer;import Java.nio.channels.filechannel;import Java.nio.channels.serversocketchannel;import Java.nio.channels.socketchannel;import Java.nio.file.paths;import Java.nio.file.standardopenoption;import org.junit.test;/* * Three cores to complete network communication using NIO: * 1. Channel: Responsible for connection * * Java.nio.channels.Channel Interface: * |--selectablechannel * | -socketchannel * |--serversocketchannel * |--datagramchannel * * |--pipe. Sinkchannel * |--pipe.sourcechannel * * 2. Buffer: Responsible for data access * * 3. Selector (Selector): is a selectablechannel multiplexer. IO Status for monitoring Selectablechannel * */public class Testblockingnio {//client @Test public void client () throws Ioexce ption{//1. Get channel Socketchannel SChannel = Socketchannel.open (New inetsocketaddress ("127.0.0.1", 9898)); FileChannel Inchannel = Filechannel.opeN (Paths.get ("1.jpg"), Standardopenoption.read); 2. Allocates a buffer of the specified size Bytebuffer buf = bytebuffer.allocate (1024); 3. Reads the local file and sends it to the service side while (Inchannel.read (BUF)! =-1) {buf.flip (); Schannel.write (BUF); Buf.clear (); }//4. Close channel Inchannel.close (); Schannel.close (); }//service-side @Test public void server () throws ioexception{//1. Get channel Serversocketchannel Sschannel = Serversocketchannel.open (); FileChannel Outchannel = Filechannel.open (Paths.get ("2.jpg"), Standardopenoption.write, standardopenoption.create); 2. Bind connection Sschannel.bind (new Inetsocketaddress (9898)); 3. Gets the channel of the client connection Socketchannel SChannel = Sschannel.accept (); 4. Allocates a buffer of the specified size Bytebuffer buf = bytebuffer.allocate (1024); 5. Receives the client's data and saves it to local while (Schannel.read (BUF)! =-1) {buf.flip (); Outchannel.write (BUF); Buf.clear (); }//6. Close channel Schannel.close (); Outchannel.close (); Sschannel.close (); } }
So to solve the above method, when there is no selector before, for the blocking situation, we can use the following method: (send complete, automatically shut down to notify the completion of the sent)
Import Java.io.ioexception;import Java.net.inetsocketaddress;import Java.nio.bytebuffer;import Java.nio.channels.filechannel;import Java.nio.channels.serversocketchannel;import Java.nio.channels.socketchannel;import Java.nio.file.paths;import Java.nio.file.standardopenoption;import Org.junit.test;public class TestBlockingNIO2 {//client @Test public void client () throws ioexception{so Cketchannel SChannel = Socketchannel.open (New inetsocketaddress ("127.0.0.1", 9898)); FileChannel Inchannel = Filechannel.open (Paths.get ("1.jpg"), Standardopenoption.read); Bytebuffer buf = bytebuffer.allocate (1024); while (Inchannel.read (BUF)! =-1) {buf.flip (); Schannel.write (BUF); Buf.clear (); } Schannel.shutdownoutput (); Receive service side feedback int len = 0; while (len = Schannel.read (BUF))! =-1) {buf.flip (); System.out.println (New String (Buf.array (), 0, Len)); Buf.clear (); } inchannel.close (); Schannel.close (); }//service-side @Test public void server () throws ioexception{serversocketchannel Sschannel = Serversocketcha Nnel.open (); FileChannel Outchannel = Filechannel.open (Paths.get ("2.jpg"), Standardopenoption.write, standardopenoption.create); Sschannel.bind (New Inetsocketaddress (9898)); Socketchannel SChannel = sschannel.accept (); Bytebuffer buf = bytebuffer.allocate (1024); while (Schannel.read (BUF)! =-1) {buf.flip (); Outchannel.write (BUF); Buf.clear (); }//Send feedback to client buf.put ("Server received data successfully". GetBytes ()); Buf.flip (); Schannel.write (BUF); Schannel.close (); OutChannel.close (); Sschannel.close (); }}
Second, selector (Selector)
The selector (Selector) is a multiplexer for the Selectablechannle object, and Selector can monitor the IO status of multiple selectablechannel at the same time, that is, using Selector enables a single thread to manage multiple Cha Nnel. Selector is the core of non-blocking IO.
The structure of Selectablechannle is as follows:
The application of the selector (Selector)
Create Selector : Create a Selector by calling the Selector.open () method .
Register Channel to selector: selectablechannel.register (Selector sel, int ops)
Selector ( Selector) Applications
When you call register (Selector sel, int ops) to register the channel with the selector, the selector listens to the channel for events that need to be specified by the second parameter ops.
Types of events that can be monitored (four constants using Selectionkey):
? READ: Selectionkey.op_read (1)
? Write: Selectionkey.op_write (4)
? Connection: Selectionkey.op_connect (8)
? Receiving: Selectionkey.op_accept (16)
If you are registering more than one event, you can use the bitwise OR operator to connect
Cases:
Selectionkey
Selectionkey: Represents the registration relationship between Selectablechannel and Selector. An event (select key) is selected each time a channel is registered with the selector. The selection key contains two sets of operations represented as integer values. Each bit of the action set represents a class of selectable operations supported by the channel of the key.
Method |
Description |
int Interestops () |
Get collection of events of interest |
int Readyops () |
Gets the collection of operations that the channel is already ready for |
Selectablechannel Channel () |
Get registration Channel |
Selector Selector () |
Return Selector |
Boolean isreadable () |
Detects if read events are ready in channal |
Boolean iswritable () |
Detects if write events are ready in channal |
Boolean isconnectable () |
Detects if the connection is ready in the Channel |
Boolean isacceptable () |
Detects if reception is ready in the Channel |
Selector Common methods of
Method |
Description |
set<selectionkey> keys () |
All the Selectionkey collections. On behalf of the channel registered on the selector |
Selectedkeys () |
The selected Selectionkey collection. Returns the selected key set for this selector |
int Select () |
Monitor all registered channel, and when they have IO operations that need to be processed, The method returns, and will add the selected Selectionkey to the due In the Selectionkey collection, the method returns the number of these Channel numbers. |
int Select (Long timeout) |
You can set the time-out select () operation |
int Selectnow () |
Executes a select () operation that returns immediately, which does not block the thread |
Selector Wakeup () |
Causes a Select () method that has not yet returned to return immediately |
void Close () |
Close the Selector |
Socketchannel
The Socketchannel in Java NiO is a channel that connects to a TCP network socket.
Operation Steps:
? Open Socketchannel
? Read and write Data
? Close Socketchannel
The Serversocketchannel in Java NiO is a channel that can listen for incoming TCP connections, just like serversocket in standard IO
code sample;
Package Com.atguigu.nio;import Java.io.ioexception;import Java.net.inetsocketaddress;import java.nio.ByteBuffer; Import Java.nio.channels.selectionkey;import Java.nio.channels.selector;import Java.nio.channels.serversocketchannel;import Java.nio.channels.socketchannel;import Java.util.Date;import Java.util.iterator;import Java.util.scanner;import org.junit.test;/* * I. Three cores for network communication using NIO: * * 1. Channel: Responsible for connection * * Java.nio.channels.Channel Interface: * |--selectablechannel * | -socketchannel * |--serversocketchannel * |--datagramchannel * * |--pipe. Sinkchannel * |--pipe.sourcechannel * * 2. Buffer: Responsible for data access * * 3. Selector (Selector): is a selectablechannel multiplexer. IO Status for monitoring Selectablechannel * */public class Testnonblockingnio {//client @Test public void client () throws ioexception{//1. Get channel Socketchannel SChannel = Socketchannel.open (New inetsocketaddress ("127.0.0.1 ", 9898)); 2. Toggle non-blocking mode schannel.configureblocking (false); 3. Allocates a buffer of the specified size Bytebuffer buf = bytebuffer.allocate (1024); 4. Send data to the server Scanner scan = new Scanner (system.in); while (Scan.hasnext ()) {String str = scan.next (); Buf.put (New Date (). toString () + "\ n" + str). GetBytes ()); Buf.flip (); Schannel.write (BUF); Buf.clear (); }//5. Close channel Schannel.close (); }//service-side @Test public void server () throws ioexception{//1. Get channel Serversocketchannel Sschannel = Se Rversocketchannel.open (); 2. Toggle non-blocking mode sschannel.configureblocking (false); 3. Bind connection Sschannel.bind (new Inetsocketaddress (9898)); 4. Get selector Selector Selector = Selector.open (); 5. Registers the channel with the selector and specifies "Listen for receive events" Sschannel.register (selector, selectionkey.op_accept); 6. Polling gets the event "ready" on the selector while (Selector.select () > 0) {//7. Gets all registered "Select keys (Listening events ready)" in the current selector Iterator<selectionkey> it = Selector.selectedkeys (). Iterator (); while (It.hasnext ()) {//8. Get ready for "ready" is the event Selectionkey SK = It.next (); 9. Determine what the specific event is ready if (sk.isacceptable ()) {//10. Get client connections if "ready to receive" Socketchan Nel sChannel = sschannel.accept (); 11. Toggle non-blocking mode schannel.configureblocking (false); 12. Register the channel on the selector schannel.register (selector, selectionkey.op_read); }else if (sk.isreadable ()) {//13. Gets the channel of the "Read Ready" state on the current selector socketchannel SChannel = (Socket Channel) Sk.channel (); 14. Read Data BYtebuffer buf = bytebuffer.allocate (1024); int len = 0; while (len = Schannel.read (buf)) > 0) {buf.flip (); System.out.println (New String (Buf.array (), 0, Len)); Buf.clear (); }}//15. Deselect key Selectionkey It.remove (); } } }}
Datagramchannel
The Datagramchannel in Java NiO is a channel that can send and receive UDP packets.
? Operation Steps:
? Open Datagramchannel
? Receive/Send data
examples;
Package Com.atguigu.nio;import Java.io.ioexception;import Java.net.inetsocketaddress;import java.nio.ByteBuffer; Import Java.nio.channels.datagramchannel;import Java.nio.channels.selectionkey;import java.nio.channels.Selector; Import Java.util.date;import java.util.iterator;import Java.util.scanner;import Org.junit.test;public class TestNonBlockingNIO2 {@Test public void Send () throws ioexception{datagramchannel dc = DATAGRAMCHANNEL.O Pen (); Dc.configureblocking (FALSE); Bytebuffer buf = bytebuffer.allocate (1024); Scanner scan = new Scanner (system.in); while (Scan.hasnext ()) {String str = scan.next (); Buf.put (New Date (). toString () + ": \ n" + str). GetBytes ()); Buf.flip (); Dc.send (buf, New inetsocketaddress ("127.0.0.1", 9898)); Buf.clear (); } dc.close (); } @Test public void receive () throws ioexception{DatagramchannelDC = Datagramchannel.open (); Dc.configureblocking (FALSE); Dc.bind (New Inetsocketaddress (9898)); Selector Selector = Selector.open (); Dc.register (selector, selectionkey.op_read); while (Selector.select () > 0) {iterator<selectionkey> it = Selector.selectedkeys (). Iterator (); while (It.hasnext ()) {Selectionkey SK = It.next (); if (sk.isreadable ()) {Bytebuffer buf = bytebuffer.allocate (1024); Dc.receive (BUF); Buf.flip (); System.out.println (New String (Buf.array (), 0, Buf.limit ())); Buf.clear (); }} it.remove (); } }}
Piping (Pipe)
The Java NIO pipeline is a one-way data connection between 2 threads. The pipe has a source channel and a sink channel. The data is written to the sink channel, which is read from the source channel.
Write data to the pipeline
Reading data from a pipeline
Data from the Read pipeline requires access to the source channel.
Call the Read () method of the source channel to read the data
Code Sample:
Import Java.io.ioexception;import java.nio.bytebuffer;import Java.nio.channels.pipe;import org.junit.Test;public Class Testpipe { @Test public void Test1 () throws ioexception{ //1. Get piping Pipe pipe = Pipe.open (); 2. Writes the data in the buffer to the pipe bytebuffer buf = bytebuffer.allocate (1024x768); Pipe.sinkchannel Sinkchannel = Pipe.sink (); Buf.put ("Send data through a one-way pipe". GetBytes ()); Buf.flip (); Sinkchannel.write (BUF); 3. Reads the data in the buffer pipe.sourcechannel Sourcechannel = Pipe.source (); Buf.flip (); int len = Sourcechannel.read (BUF); System.out.println (New String (Buf.array (), 0, Len)); Sourcechannel.close (); Sinkchannel.close (); } }
Java NiO Learning Three: NiO's non-blocking network communication