a server's ability to handle numerous client requests within a reasonable time is dependent on how to adjust tively it uses I/O streams. A server that caters to hundreds of clients simultaneously must be able to use I/O services concurrently. until JDK 1.4 (aka Merlin), the Java platform did not support nonblocking I/O CILS. with an almost one-to-one ratio of threads to clients, servers written in the Java language were susceptible to enormous thread overhead, which resulted in both performance problems and lack of scalability.
To address this issue, a new set of classes have been introduced to the Java platform with the latest release. merlin's Java. NIO package is chock full of tricks for resolving thread overhead, the most important being the newSelectablechannel
AndSelector
Classes.ChannelRepresents a means of communication between a client and a server.SelectorIs analogous to a Windows message loop, in which the selector captures the various events from different clients and dispatches them to their respective event handlers. in this article, we'll show you how these two classes function together to create a nonblocking I/O mechanic for the Java platform.
I/O programming before Merlin
We'll start with a look at a basic, pre-Merlin server-socket program. In the lifetime ofServersocket
Class, the important functions are as follows:
- Accept incoming connections
- Read requests from clients
- Service those requests
Let's take a look at each of these steps using code snippets to define strate. First, we create a newServersocket
:
Serversocket S = new serversocket (); |
Next, we want to accept an incoming call. A callAccept ()
Shocould do the trick here, but there's a little trap you have to watch:
Socket conn = S. Accept (); |
The callAccept ()
Blocks until the server socket accepts a client request for connection. Once a connection is established, the server reads the client requests, usingLinenumberreader
. BecauseLinenumberreader
Reads data in chunks until the buffer is full, the call blocks on a read. The following snippet showsLinenumberreader
In action (blocks and all ).
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
Method also blocks until data is available, as doesWrite
Method.
Figure 1 depicts the typical workings of a server. The bold lines represent blocking operations.
Figure 1. A typical server in action
Prior to JDK 1.4, liberal use of threads was the most typical way of getting around blocking. but this solution created its own problem -- namely thread overhead, which impacts both performance and scalability. with the arrival of Merlin and the java. NIO package, however, everything has changed.
In the sections that follow, we'll look at the foundations of Java. NiO, and then apply some of what we 've learned to revising the server-socket example described above.
Back to Top
The reactor Pattern
The principal force behind the design of NiO is the reactor design pattern. server applications in a distributed system must handle multiple clients that send them service requests. before invoking a specific service, however, the server application must demultiplex and dispatch each incoming request to its corresponding service provider. the reactor pattern serves precisely this function. it allows event-driven applications to demultiplex and dispatch service requests, which are then delivered concurrently to an application from one or more clients.
Core functions of the reactor Pattern
- Demultiplexing events
- Dispatching events to their corresponding event handlers
The reactor pattern is closely related to the observer pattern in this aspect: All dependents are informed when a single subject changes. the observer pattern is associated with a single source of events, however, whereas the reactor pattern is associated with multiple sources of events.
See resources to learn more about the reactor pattern.
Back to Top
Channels and selectors
NIO's nonblocking I/O mechanic is built aroundSelectorsAndChannels.Channel
Class represents a communication mechanic between a server and a client. In keeping with the reactor pattern,Selector
Class is a multiplexorChannel
S. It demultiplexes incoming client requests and dispatches them to their respective request handlers.
We'll look closely at the respective functions ofChannel
Class andSelector
Class, and at how the two work together to create a nonblocking I/O implementation.
What the channel does
A channel represents an open connection to an entity such as a hardware device, a file, a network socket, or a program component that is capable of parameter Ming one or more distinct I/O operations, such as reading or writing. NIO channels can be asynchronously closed and interrupted. so, if a thread is blocked in an I/O operation on a channel, another thread can close that channel. similarly, if a thread is blocked in an I/O operation on a channel, another thread can interrupt that blocked thread.
Figure 2. class hierarchy for Java. NiO. Channels
As figure 2 shows, there are quite a few Channel interfaces in the Java. NiO. Channels package. We're mainly concerned withJava. NiO. channels. socketchannel
AndJava. NiO. channels. serversocketchannel
Interfaces. These channels can be treated as replacementsJava.net. Socket
AndJava.net. serversocket
, Respectively. channels can be used in a blocking or a nonblocking mode, though of course we will focus on using channels in nonblocking mode.
Creating a nonblocking Channel
We have two new classes to deal with in order to implement basic nonblocking socket read and write operations. These areInetsocketaddress
Class from the java.net package, which specifies where to connect to, andSocketchannel
Class from the java. NiO. Channels package, which does the actual reading and writing operations.
The code snippets in this section show a revised, nonblocking approach to creating a basic server-socket program. note the changes between these code samples and those used in the first example, starting with the addition of our two new classes:
String host =...; inetsocketaddress socketaddress = new inetsocketaddress (host, 80); socketchannel channel = socketchannel. open (); Channel. Connect (socketaddress ); |
The role of the buffera is an abstract class that contains data of a specific primitive data type. it is basically a wrapper around und a fixed-size array with getter/setter methods that make its contents accessible. the
Buffer
Class has a number of subclasses, as follows:
Bytebuffer
Charbuffer
Doublebuffer
Floatbuffer
Intbuffer
Longbuffer
Protocol Buffer
Bytebuffer
Is the only class that supports Reading and Writing from and to the other types, since the other classes are type specific. Once connected, data can be read from or written to the channel withBytebuffer
Object. See resources to learn more aboutBytebuffer
.
To make the channel nonblocking, we callConfigureblockingmethod (false)
On the channel, as shown here:
Channel. configureblockingmethod (false ); |
In blocking mode, a thread will block on a read or a write until the operation is completely finished. if during a read, data has not completely arrived at the socket, the thread will block on the read operation until all the data is available.
In nonblocking mode, the thread will read whatever amount of data is available and return to perform other tasks. IfConfigureblockingmethod ()
Is passed true, the channel's behavior will be exactly the same as that of a blocking read or write onSocket
. The one major difference, mentioned above, is that these blocking reads and writes can be interrupted by other threads.
TheChannel
Alone isn' t enough to create a nonblocking I/O implementation.Channel
Class must work in conjunction withSelector
Class to achieve nonblocking I/O.
What the selector does
TheSelector
Class plays the role ofReactor
In the reactor pattern scenario.Selector
Multiplexes events on severalSelectablechannels
. EachChannel
Registers events withSelector
. When events arrive from clients,Selector
Demutliplexes them and dispatches the events to the correspondingChannel
S.
The simplest way to createSelector
Is to useOpen ()
Method, as shown below:
Selector selector = selector. open (); |
Channel meets Selector
EachChannel
That has to service client requests must first create a connection. The code below createsServersocketchannel
CalledServer
And binds it to a local port:
Serversocketchannel serverchannel = serversocketchannel. open (); serverchannel. configureblocking (false); inetaddress IA = inetaddress. getlocalhost (); inetsocketaddress ISA = new inetsocketaddress (IA, Port); serverchannel. socket (). BIND (ISA ); |
EachChannel
That has to service client requests must next register itself withSelector
.Channel
Shocould be registered according to the events it will handle. For instance,Channel
That accepts incoming connections shoshould be registered as shown here:
Selectionkey acceptkey = channel. Register (selector, selectionkey. op_accept ); |
AChannel
'S registry withSelector
Is represented bySelectionkey
Object.Key
Is valid until one of these three conditions is met:
- The
Channel
Is closed.
- The
Selector
Is closed.
- The
Key
Itself is canceled by invoking itsCancel ()
Method.
TheSelector
Blocks onSelect ()
Call. It then waits until a new connection is made, another thread wakes it up, or another thread interrupts the original blocked thread.
Registering the server
Server
IsServersocketchannel
That registers itself withSelector
To accept all incoming connections, as shown here:
Selectionkey acceptkey = serverchannel. Register (SEL, selectionkey. op_accept); While (acceptkey. selector (). Select ()> 0 ){...... |
AfterServer
Is registered, we iterate through the set of keys and handle each one based on its type. After a key is processed, it is removed from the list of ready keys, as shown here:
Set readykeys = SEL. selectedkeys (); iterator it = readykeys. iterator (); While (it. hasnext () {selectionkey key = (selectionkey) it. next (); it. remove ();............} |
If the key is acceptable, the connection is accepted and the channel is registered for further events such as read or write operations. if the key is readable or writable, the server indicates it is ready to read or write data on its end:
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 );}} |
Back to Top
Abracadabra -- nonblocking server socket appear!
The final part of this introduction to nonblocking I/O in JDK 1.4 is left to you: running the example.
In this simple nonblocking server-socket example, the server reads a file name sent from the client, displays the file contents, and writes the contents back to the client.
Here's what you need to do to run the example:
- Install JDK 1.4 (see resources ).
- Copy both source files onto your directory.
- Compile and run the server
Java nonblockingserver
.
- Compile and run the client
Java client
.
- Input the name of a text or Java file in the directory where the class files are present.
- The server will read the file and send its contents to the client.
- The client will print out the data already ed from the server. (Only 1024 bytes will be read since that is the limit of
Bytebuffer
Used .)
- Close the client by entering the command to quit or shutdown.
Back to Top
Conclusion
The new I/O packages from Merlin cover a broad scope. The major advantage of Merlin's new nonblocking I/O implementation is twofold: threads no longer block on reads or writes andSelector
Is able to handle multiple connections, greatly cing server application overhead.
We have highlighted these two primary advantages of the new java. Nio package. We hope that you will apply what you 've learned here to your real-time application development efforts.
Back to Top
Download
Name |
Size |
Download Method |
J-javaio.zip |
3kb |
HTTP |
Information about download Methods