March 12, 2002
The Java technology platform should have provided non-blocking I/O mechanisms for a long time. Fortunately, Merlin (JDK 1.4) has a magic wand that applies in almost every scenario, and the blocking state of the blocked I/O is exactly what the magician is doing. Software engineers Aruna kalagnanam and Balu g introduced Merlin's new I/O package-java. niO (NIO)-This non-blocking feature, and uses a socket programming example to show you what NiO can do. Click
Discussion, In
The Forum will share your experiences with the author and other readers about this article.
The server's ability to process a large number of client requests within a reasonable period of time depends on the efficiency of the server's use of the I/O Stream. At the same time, servers that provide services to hundreds of clients must be able to concurrently use the I/O service. The Java platform does not support non-blocking I/O calls until JDK 1.4 (Merlin. For a server written in Java, the ratio of the thread to the client is almost the same, which is vulnerable to a large number of thread overhead. The result is that both performance problems and scalability are caused.
To solve this problem, the latest release of the Java platform introduces a new group of classes. Merlin's Java. Nio package is full of skills to solve thread overhead problems. The most important thing in the package is the new
SelectableChannel
Class andSelector
Class.
Channel)It is a communication method between the client and the server.Selector)Similar to Windows message loop, it captures various events from different clients and distributes them to corresponding event handlers. In this article, we will show you how these two classes work together to create a non-blocking I/O Mechanism for the Java platform.
I/O programming before Merlin
We will start from the basic server-socket (server-socket) program before Merlin. InServerSocket
Important Functions of the class are as follows:
- Accept incoming connections
- Read requests from clients
- Provide services for requests
Let's take a look at each of the above steps. We use code snippets to describe them. First, we create a newServerSocket
:
ServerSocket s = new ServerSocket(); |
Next, we need to accept incoming calls. Here, callaccept()
You should be able to complete the task, but there is a small trap:
Socket conn = s.accept( ); |
Pairaccept()
Until the server socket accepts a client request for connection. Once a connection is established, the server uses
LineNumberReader
Read client requests. Because
LineNumberReader
Data is read in batches only when the buffer is full, so this call is blocked during reading. The following snippet shows
LineNumberReader
(Blocking, etc ).
InputStream in = conn.getInputStream();InputStreamReader rdr = new InputStreamReader(in);LineNumberReader lnr = new LineNumberReader(rdr);Request req = new Request();while (!req.isComplete() ){ String s = lnr.readLine(); req.addLine(s);} |
InputStream.read()
Is another way to read data. Unfortunately,
read
The method must be blocked until the data is available,
write
The same is true ,.
Figure 1 depicts a typical server process. A black line indicates a blocking operation.
Figure 1. Typical servers at work
Before JDK 1.4, free use of threads is the most typical way to handle blocking problems. However, this solution produces its own problem-thread overhead, which affects both performance and scalability. However, with the advent of Merlin and Java. Nio packages, everything has changed.
In the following sections, we will examine the basic idea of Java. NiO, and then apply some of the knowledge we have learned to modify the server-socket example described above.
Reactor Pattern)
The foundation of NiO design is the design mode of reactors. Server Applications in distributed systems must process multiple clients that send service requests to them. However, before calling a specific service, the server application must allocate and distribute each incoming request to the corresponding service provider. The reactor mode is suitable for this function. It allows event-driven applications to distribute and distribute service requests concurrently from one or more clients to the application.
|
Core functions of the reactor model
- Multiplexing of events
- Distribute events to corresponding event handlers
|
|
The reactor pattern is very similar to the observer pattern in this respect: When a subject changes, all dependent bodies are notified. However, the observer mode is associated with a single event source, while the reactor mode is associated with multiple event sources.
See
For more information about the reactor mode, see references.
Channels and selectors
NIO's non-blocking I/O mechanism is centered aroundSelectorAndChannelBuilt.Channel
Class indicates a communication mechanism between the server and the client. Consistent with the reactor mode,
Selector
Class isChannel
.
Selector
Class is used to distribute incoming client requests to multiple channels and distribute them to their respective request handlers.
We will take a closer lookChannel
Class and
Selector
And how the two classes work together to create non-blocking I/O implementations.
What do channels do?
A channel represents a connection to an object (for example, a hardware device, file, network socket, or program component that can perform one or more different I/O operations (for example, read or write). The NiO channel can be closed and interrupted asynchronously. Therefore, if a thread blocks the I/O operations of a channel, the other thread can close the channel. Similarly, if a thread is blocked in the I/O operation of a channel, the other thread can interrupt the blocking thread.
Figure 2. java. NiO. Channels class hierarchy
As shown in figure 2, there are many Channel interfaces in the Java. NiO. Channels package. We are mainly concerned aboutjava.nio.channels.SocketChannel
Interfaces and
java.nio.channels.ServerSocketChannel
Interface. These two interfaces can be used to replace
java.net.Socket
Andjava.net.ServerSocket
. Although we will certainly focus on using channels in a non-blocking manner, the channel can be used in blocking or non-blocking mode.
Create a non-blocking Channel
To implement basic non-blocking Socket read and write operations, we need to process two new classes. They are from the java.net package.InetSocketAddress
Class, which specifies the connection location and from the java. NiO. Channels package
SocketChannel
Class, which performs the actual read and write operations.
The code snippets in this section show a modified, non-blocking method to create a basic server-socket program. Note the changes between these code samples and the code used in the first example, starting with adding two new classes:
String host = ......; InetSocketAddress socketAddress = new InetSocketAddress(host, 80); SocketChannel channel = SocketChannel.open(); channel.connect(socketAddress); |
|
Buffer role Buffer Is an abstract class that contains specific basic data types. Essentially, it is a package that wraps an array of fixed sizes with the getter/setter method. These getter/setter methods allow access to the buffer content.
Buffer The class has many subclasses, as shown below:
ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
ByteBuffer Is the only class that supports reading and writing other types, because other classes are specific to types. Once connected, you can use
ByteBuffer The object reads data from or writes data to the channel. See References
ByteBuffer .
|
|
To make the channel non-blocking, we callconfigureBlockingMethod(false)
, As shown below:
channel.configureBlockingMethod(false); |
In blocking mode, the thread blocks reading or writing until the read or write operations are complete. If the data has not completely reached the socket at the time of reading, the thread will block the reading operation until the data is available.
In non-blocking mode, the thread reads available data (no matter how much) and then returns to execute other tasks. If true is passedconfigureBlockingMethod()
In
Socket
The behavior for blocking reading or writing is the same. The only major difference is that these blocked reads and writes can be interrupted by other threads.
IndependentChannel
Creating non-blocking I/O implementations is not enough. To implement non-blocking I/O,
Channel
The class must beSelector
Class.
What do selector do?
In the reactor mode,Selector
Class
Reactor
Role.Selector
For multiple
SelectableChannels
. Each
Channel
DirectionSelector
Register an event. When the event arrives from the client,
Selector
Multiple channels are used to distribute these events to the corresponding
Channel
.
CreateSelector
The simplest way is to use
open()
Method:
Selector selector = Selector.open(); |
Channel encounter Selector
EachChannel
You must first create a connection. The following code is called
Server
OfServerSocketChannel
And bind it to the local port:
ServerSocketChannel serverChannel = ServerSocketChannel.open();serverChannel.configureBlocking(false);InetAddress ia = InetAddress.getLocalHost();InetSocketAddress isa = new InetSocketAddress(ia, port );serverChannel.socket().bind(isa); |
EachChannel
You must continue
Selector
Register.Channel
The event to be handled should be registered based on it. For example
Channel
You should register as follows:
SelectionKey acceptKey = channel.register( selector,SelectionKey.OP_ACCEPT); |
Channel
DirectionSelector
For registration
SelectionKey
Object Representation. Meet one of the following three conditions,
Key
It becomes invalid:
Channel
Disabled.
Selector
Disabled.
- By calling
Key
Ofcancel()
Method
Key
Canceled.
Selector
Inselect()
The call is blocked. Then, it starts to wait until a new connection is established, or another thread wakes it up, or another thread interrupts the original blocked thread.
Registration Server
Server
IsSelector
Register to accept all incoming connections
ServerSocketChannel
, As shown below:
SelectionKey acceptKey = serverChannel.register(sel, SelectionKey.OP_ACCEPT); while (acceptKey.selector().select() > 0 ){ ...... |
Server
After registration, a set of keywords are processed iteratively based on the type of each key. After a keyword is processed, it is removed from the ready keys list, as shown below:
Set readyKeys = sel.selectedKeys(); Iterator it = readyKeys.iterator();while (it.hasNext()) {SelectionKey key = (SelectionKey)it.next(); it.remove(); .... .... .... } |
If the keyword is acceptable (acceptable), accept the connection and register the channel to accept more events (for example, read or write operations ). If the keyword is readable or writable, the server instructs you that it is ready to read and write local data:
SocketChannel socket;if (key.isAcceptable()) { System.out.println("Acceptable Key"); ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); socket = (SocketChannel) ssc.accept(); socket.configureBlocking(false); SelectionKey another = socket.register(sel,SelectionKey.OP_READ|SelectionKey.OP_WRITE);}if (key.isReadable()) { System.out.println("Readable Key"); String ret = readMessage(key); if (ret.length() > 0) { writeMessage(socket,ret); } }if (key.isWritable()) { System.out.println("Writable Key"); String ret = readMessage(key); socket = (SocketChannel)key.channel(); if (result.length() > 0 ) { writeMessage(socket,ret); } } |
Why? alimail-non-blocking server socket is quick!
The last part of the introduction to non-blocking I/O in JDK 1.4 is left to you: Run this example.
In this simple non-blocking server-socket example, the server reads the file name sent from the client, displays the content of the file, and then writes the content back to the client.
Here is what you need to do to run this example:
- Install JDK 1.4 (see
References ).
- Set
Copy the source code file to your directory.
- Compile and run the server,
java NonBlockingServer
.
- Compile and run the client,
java Client
.
- Enter the name of a text file or Java file in the directory where the class file is located.
- The server will read the file and send its content to the client.
- The client prints the data received from the server. (Because
ByteBuffer
So only 1024 bytes are read .)
- Enter the quit or shutdown command to close the client.
Conclusion
Merlin's new I/O package covers a wide range. Merlin's new non-blocking I/O implementation has two main advantages: the thread is no longer blocked during reading or writing, andSelector
It can process multiple connections, greatly reducing the overhead of server applications.
We have already focused on the two advantages of the new java. Nio package. We hope that you will apply the knowledge learned here to your actual application development work.