According to UNIX network programming, Io models can be divided into: Blocking Io, non-blocking Io, Io multiplexing, signal-driven Io and asynchronous Io, according to the POSIX standard, there are only two types: Synchronous Io and asynchronous Io.
Synchronous Io and asynchronous IoHow to differentiate it?
First, an IO operation is divided into two steps: initiating an IO request and the actual Io operation. The difference between synchronous Io and asynchronous Io lies in whether the second step is blocked, if the actual Io reads and writes block the request process, it is synchronous Io, so blocking Io, non-blocking Io, taking Io, and signal-driven Io are both synchronous Io. If not blocked, but the operating system will help you complete the IO operation and then return the result to you, that is, asynchronous Io.
How can I distinguish between blocking Io and non-blocking io?
The difference between blocking Io and non-blocking Io lies in the first step: whether or not the initiating Io request will be blocked. If blocking is completed, it is the traditional blocking Io. If it is not blocked, it is non-blocking Io.
The main improvement of Java NiO 2.0 is the introduction of asynchronous io (including files and networks). Here we mainly introduce the use of Asynchronous Network I/O APIs and the design of the framework. Take the TCP server as an example. First, let's take a look at the new classes and interfaces introduced to support AIO:
Java. NiO. channels. asynchronouschannel indicates that a channel supports asynchronous Io operations.
Java. NiO. channels. asynchronousserversocketchannel serversocket AIO version, TCP server creation, binding address, listening port, etc.
Java. NiO. channels. asynchronoussocketchannel is a stream-oriented asynchronous socket channel, indicating a connection.
Java. NiO. channels. asynchronouschannelgroup manages asynchronous channel groups for resource sharing. An asynchronouschannelgroup is bound to a thread pool, which executes two tasks: Processing Io events and distributing completionhandler. when creating an asynchronousserversocketchannel, You can input an asynchronouschannelgroup. The asynchronoussocketchannel created through asynchronoussocketchannel belongs to the same group and shares resources.
The callback interface of the asynchronous Io operation result of Java. NiO. channels. completionhandler is used to define the callback work after the IO operation is completed. The aio api allows two methods to process asynchronous operation results: the returned future mode or the completionhandler is registered. I recommend the completionhandler method, these handler calls are distributed by the thread pool of asynchronouschannelgroup. Obviously, the size of the thread pool is a key factor in performance. Asynchronouschannelgroup allows you to bind different thread pools and create them using three static methods:
Public static asynchronouschannelgroup withfixedthreadpool (INT nthreads, threadfactory) throws ioexception
Public static asynchronouschannelgroup withcachedthreadpool (executorservice executor, int initialsize)
Public static asynchronouschannelgroup withthreadpool (executorservice executor) throws ioexception
You need to adjust the configuration according to the specific application. From the framework perspective, you need to expose such configuration options to the user.
After introducing the main TCP interfaces and classes introduced by AIO, let's imagine how to design the next AIO framework. The reactor mode is generally used for reference to the design of the non-blocking NiO framework. React is responsible for event registration, select, and event distribution. Correspondingly, asynchronous Io has a proactor mode, proactor is responsible for distributing completionhandler. view a typical Io write process to see the differences between the two:
Reactor: Send (MSG)-> whether the message queue is empty, if it is empty-> Register op_write with reactor, then return-> reactor select-> trigger writable, notify the user thread to handle the issue-> cancel writable first (many people encounter the problem of CPU 100% because it is not logged out), and process writeable. if not completely written, continue to register op_write. note that the writing is still being processed by the user thread.
Proactor: Send (MSG)-> whether the message queue is empty. If it is empty, initiate an asynchronous read call, register completionhandler, and return. -> The operating system writes your message and returns the result (number of bytes written) to proactor.-> proactor distributes completionhandler. it can be seen that the write operation is being processed by the operating system without the involvement of user threads. In fact, asynchronouschannelgroup plays the role of proactor in AIO APIs.
Completionhandler has three methods, which correspond to callback processing when the processing is successful, failed, or canceled (by returning future:
Public interface completionhandler {
Void completed (V result, a attachment );
Void failed (throwable EXC, A attachment );
Void canceled (A attachment );
}
The generic parameter V indicates the IO call result, and a is the attchment passed in when the call is initiated.
After a preliminary introduction of the classes and interfaces introduced by AIO, let's take a look at how a typical TCP server is started, how to accept connections, and how to process read and write.CodeAll are the code in the AIO branch of yanf4j, from SVN checkout, SVN address: http://yanf4j.googlecode.com/svn/branches/yanf4j-aio
Step 1: Create an asynchronousserversocketchannel. Create an asynchronouschannelgroup before creating the channel. As mentioned above, the listener can bind an asynchronouschannelgroup. All connections established through this listener belong to the same asynchronouschannelgroup and share:
This. asynchronouschannelgroup = asynchronouschannelgroup. withcachedthreadpool (executors. newcachedthreadpool (), this. threadpoolsize );
Then Initialize an asynchronousserversocketchannel through the open method:
This. serversocketchannel = asynchronousserversocketchannel. Open (this. asynchronouschannelgroup );
Set some TCP options through the socketoption class introduced by NIO 2.0:
This. serversocketchannel. setoption (standardsocketoption. so_reuseaddr, true );
This. serversocketchannel. setoption (standardsocketoption. so_rcvbuf, 16*1024 );
Bind local address:
This. serversocketchannel. BIND (New inetsocketaddress ("localhost", 8080), 100); 100 specifies the size of the queue waiting for connection (backlog ).
Are you finished? No, the most important listening work hasn't started yet. The listening port is to wait for the connection to come up so that accept can generate an asynchronoussocketchannel to indicate a new connection. Therefore, an Accept call must be initiated, the call is asynchronous. After the connection is established, the operating system returns the final result asynchronoussocketchannel to you:
Public void pendingaccept (){
If (this. started this. serversocketchannel. isopen () {This. acceptfuture = This. serversocketchannel. Accept (null, new acceptcompletionhandler ());
} Else {
Throw new illegalstateexception ("controller has been closed ");
}
Note that duplicate accept calls will throw pendingacceptexception, as well as read and write mentioned later. The first parameter of the accept method is the attchment you want to pass to the completionhandler. The second parameter is the registered completionhandler for callback, and the final result future is returned. you can handle the future. The more recommended method here is to register a completionhandler. so what does accept completionhandler do?
Obviously, a naked asynchronoussocketchannel is not enough. We need to encapsulate it into a session. A session indicates a connection (iosession in Mina ), it contains a buffered message queue and some other resources. After the connection is established, unless your server is only ready to accept one connection, you need to continue calling pendingaccept later to initiate another accept request:
Private final class acceptcompletionhandler implements
Completionhandler {
@ Override
Public void canceled (Object attachment ){
Logger. Warn ("accept operation was canceled ");
}