I. Synchronous blocking IO
bio is a blocking IO, network communication for multi-client connection, the server is always consistent with the number of client threads to handle each client task, that is, the number of clients and threads 1:1, and read and write operations in the room block, when you have thousands of clients to connect, Causes the server to constantly establish new threads, resulting in low-pass resources, the subsequent client is unable to connect to the server, and even the connected client is not always in the server to interact, it is likely to only occupy resources.
Two. Pseudo-Asynchronous IO
The pseudo-asynchronous IO is optimized for synchronous IO, and the backend handles all client requests through a thread pool and task queue, and when it is returned to the thread pool, the principle of the thread pool is similar to the database connection pool, which reduces the time of thread creation and destruction. No matter how many client connections are these fixed threads of processing, this is a lot of client and server information interaction is a very small situation, is a good way to handle, but think of a situation, when there is a client's reading information is very slow, the server writes to its operation will be very slow, even blocked for a long time, Because threads in the thread pool are limited, when a client needs to allocate a thread, it causes the new task to wait for the blocked client to release the thread in the queue. When the task queue is full, a large number of users will have a connection timeout. In fact, pseudo-asynchronous IO is also a synchronous blocking IO.
Three . Javanio principle
To address the two blocking IO flaws above,Java was added to the 1.4 release of NiO, also known as the new IO, asynchronous IO model. In network communication, NIO also provides Socketchannel and Serversocketchannel two different socket channels to implement, can set up the blocking residual non-blocking mode, in order to achieve high load and high concurrency to take a non-blocking mode. NIO uses buffer buffers to read and write data, buffers are fixed size, and the internal state records how much data is placed or taken out. Unlike blocking IO, blocking IO uses a blocking stream (stream) to read and write, the stream is one-way only reading data in one direction or writing data, and the channel is bidirectional, you can send and read data on the channel at the same time, and is non-blocking, in the absence of data readable writable can do other things.
NIO has improved the one-to-one or m:n models above. The server takes only one thread to process all client threads, which requires creating a selector and registering it on the channel you want to monitor (note that it is done by channel). and returns a Selectorkey instance (containing the channel and select and the operations of interest), selector as if it were an observer, by constantly polling for a set of channels on which there are no waiting actions to occur, and when waiting for events to happen, you can do other things, When there is an operation of interest on the channel, the channel enters the ready state.
The Slector Select method blocks the waiting and not ready channel, when a ready channel appears or waits for a timeout to return, the number of ready channels, and if the wait timeout returns the channel that the -1,selectedkeys method returns to.
The following code is attached
This is the interface that handles the channel of interest, because he can be placed on multiple servers, so he made an interface.
Package Nio;import Java.io.ioexception;import Java.nio.channels.selectionkey;public interface Tcpprotocol {void Handleaccept (Selectionkey key) throws Ioexception;void Handleread (Selectionkey key) throws Ioexception;void Handlewrite (Selectionkey key) throws IOException;}
<span style= "font-family:fangsong_gb2312;" > This is a specific implementation of the above interface </span>package Nio;import Java.io.ioexception;import java.nio.bytebuffer;import Java.nio.channels.selectionkey;import Java.nio.channels.serversocketchannel;import Java.nio.channels.socketchannel;public class Selectorprotocol implements Tcpprotocol {private int bufSize;p ublic Selectorprotocol (int buffsize) {this.bufsize = buffsize;}//service-side channel is ready to receive new client connections public void Handleaccept (Selectionkey Key) throws IOException {Socketchannel Clntchan = ((Serversocketchannel) Key.channel ()). Accept (); Clntchan.configureblocking (FALSE); Registers the selector with the client channel to which it is connected and specifies that the channel key value is Op_read, specifying the associated attachment Clntchan.register for that channel (Key.selector (), Selectionkey.op_read, by Tebuffer.allocate (bufSize)); }//Client channel is ready to read data from the channel to buffer public void Handleread (Selectionkey key) throws ioexception{Socketchanne L Clntchan = (Socketchannel) key.channel (); Gets the attachment associated with the channel, which is the buffer bytebufferBUF = (bytebuffer) key.attachment (); Long bytesread = Clntchan.read (BUF); If the Read () method returns 1, indicating that the client has closed the connection, the client has received data that is equal to the number of bytes sent, and can safely close if (bytesread = =-1) {Clntchan.close () ; }else if (Bytesread > 0) {//If the buffer is always read into the data, set the operation that is of interest to the channel to be a readable writable key.interestops (Selectionkey.op_read | Selectionkey.op_write); }}//client channel is ready to write data from buffer to channel public void Handlewrite (Selectionkey key) throws IOException {//Get The buffer associated with the channel, containing the data previously read bytebuffer BUF = (bytebuffer) key.attachment (); Resets the buffer, ready to write data to the channel Buf.flip (); Socketchannel Clntchan = (socketchannel) key.channel (); Writes data to the channel Clntchan.write (BUF); if (!buf.hasremaining ()) {//If the data in the buffer has all been written to the channel, the operation that is of interest to the channel is set to a readable key.interestops (selectionkey.op_read); }//To make room for reading more data buf.compact (); } }
Client
Package Nio;import Java.net.inetsocketaddress;import Java.net.socketexception;import java.nio.bytebuffer;import Java.nio.channels.socketchannel;public class Tcpechoclientnonblocking {public static void main (String args[]) throws exception{//the first parameter as the hostname of the server to be connected or ipstring server = "localhost";//The second parameter is the string to be sent to the server byte[] argument = "nihaopengyou". GetBytes ();//If there is a third parameter, as the port number, if not, the port number is set to 7int Servport = 2002;//Create a channel and set to nonblocking mode Socketchannel Clntchan = Socketchannel.open (); clntchan.configureblocking (false);//initiates connection to the server if (!clntchan.connect (New Inetsocketaddress ( Server, Servport)) {//Continuously polls the connection state until the connection is complete while (!clntchan.finishconnect ()) {////During the waiting time for the connection, other tasks can be performed to give full play to the asynchronous characteristics of nonblocking IO// Here to demonstrate the use of the method, just print "." System.out.print ("."); }}//in order to print with the back "." Distinguish, here output newline character System.out.print ("\ n"),//instantiate the buffer to read and write respectively bytebuffer writebuf = bytebuffer.wrap (argument); Bytebuffer readbuf = bytebuffer.allocate (argument.length);//The total number of bytes received int totalbytesrcvd = 0; Each time the read () method is called, the number of bytes received by the int bytesrcvd; The loop executes until the number of bytes received is equal to the number of bytes in the string being sent while (totalbytesRCVD < Argument.length) {//If there are remaining bytes in the buffer used to write data to the channel, continue to write the data to the channel if (writebuf.hasremaining ()) {Clntchan.write ( WRITEBUF);} If read () receives 1, indicates that the server is closed, throws an exception if ((BYTESRCVD = Clntchan.read (readbuf)) = =-1) {throw new SocketException ("Connection Closed prematurely ");} Calculates the total number of bytes received TOTALBYTESRCVD + = bytesrcvd;//while waiting for communication to complete, the program can perform other tasks to reflect the asynchronous nature of nonblocking IO//Here to demonstrate the use of this method, just keep printing "." System.out.print ("."); }//prints the received data System.out.println ("Received:" + New String (Readbuf.array (), 0, TOTALBYTESRCVD));//Close channel Clntchan.close () ;}}
Server
Package Nio;import Java.io.ioexception;import Java.net.inetsocketaddress;import Java.nio.channels.SelectionKey; Import Java.nio.channels.selector;import Java.nio.channels.serversocketchannel;import Java.util.Iterator;public Class tcpserverselector{//buffer length private static final int BUFSIZE = N,//select method waits for the channel to be prepared for the longest time private static final int TIM Eout = 3000; public static void Main (string[] args) throws IOException {if (Args.length < 1) {throw new IllegalArgumentException ("Par Ameter (s): <Port> ... "); Create a selector selector selector = Selector.open (); for (String Arg:args) {//Instantiate a channel serversocketchannel Listnchannel = Serversocketchannel.open ();//Binds the channel to the specified port Listnchannel.socket (). bind (New Inetsocketaddress (Integer.parseint (ARG)) ); SYSTEM.OUT.PRINTLN ("Start Server" +integer.parseint (ARG));//configuration channel is non-blocking mode listnchannel.configureblocking (false);// Register selectors to each channel Listnchannel.register (selector, selectionkey.op_accept);} Create an object that implements the Protocol interface Tcpprotocol Protocol = new Selectorprotocol (BUFSIZE);//Continuously polls the Select method to obtain a prepared channelThe associated key set while (true) {//waits until a channel is ready for the I/O operation if (Selector.select (TIMEOUT) = = 0) {/////While waiting for channel preparation, you can also perform other tasks asynchronously,//here Simply print " ." System.out.print ("."); Continue;} Gets the iterator instance of the key collection associated with the prepared channel iterator<selectionkey> keyiter = Selector.selectedkeys (). iterator ();// The loop gets each key value in the collection while (Keyiter.hasnext ()) {Selectionkey key = Keyiter.next ();//If the server-side channel is interested in the I/O operation is acceptif ( Key.isacceptable ()) {protocol.handleaccept (key);} If the client channel is interested in an I/O operation of Readif (Key.isreadable ()) {protocol.handleread (key);} If the key value is valid and its corresponding client channel is interested in the I/O operation for WriteIf (Key.isvalid () && key.iswritable ()) {protocol.handlewrite (key);} You need to manually remove the current keykeyiter.remove () from the key set; }}}}
Operation Result:
Javanio principle (including code) and comparison with synchronous blocking IO, pseudo asynchronous IO