Non-Blocking Connections

Last month's column introduced java.nio, one of the most significant new packages found in Java 2 Standard Edition Version 1.4. java.nio finally adds high-performance I/O features -- memory-mapped files, non-blocking I/O, and managed buffers -- to Java.

Last month’s column introduced java.nio, one of the most significant new packages found in Java 2 Standard Edition Version 1.4. java.nio finally adds high-performance I/O features — memory-mapped files, non-blocking I/O, and managed buffers — to Java.

Last month’s column focused on Buffer, a new set of classes that holds data in linear, sequential storage. Buffer classes can be used to store and retrieve data without incurring the overhead of object allocation and garbage collection. However, a Buffer is useless if it isn’t connected to sources that add data to the Buffer and consumers that extract data. That’s where channels come in: the new java.nio .channels.* classes add data to Buffers and extract data from Buffers.

Changing to Channels

A Channel is simply a connection between a ByteBuffer and an endpoint, either a socket or file. Indeed, the four Channel classes are divided into two sets: SocketChannel, ServerSocketChannel, and DatagramChannel for sockets, and FileChannel for files.

While Channel is similar in purpose to Stream and Reader, Channel is not a replacement for those classes. Instead, Channel joins Stream and Reader as a fundamental Java capability.

In fact, in the case of files, you have to combine Stream and Channel to memory-map files and buffer I/O. Specifically (at least in 1.4), none of the classes in java.io can read from or write to a Buffer. Additionally, you cannot create a FileChannel directly. Instead, you have to combine classes from java.io and java.nio to create, open, and buffer from a file.

For example, the following code (which we’ll build on as we go) creates a FileInputStream named inData, and a FileChannel called inChannel associated with that file:

FileInputStream inData =
new FileInputStream(“input.dat”);
FileChannel inChannel =

Note that the FileChannel is not created directly via new() (as FileInputStream is). Instead, you first create the stream, and then call inData.getChannel() to create the channel.

Once you’ve created a FileChannel, you can use that class’ size() method to find the number of bytes in the file. You can use that result with the read(ByteBuffer, long) method to fill the specified ByteBuffer with data from the channel.

For instance, the following code extends the last example by reading a file into a ByteBuffer using inChannel:

long inSize = inChannel.size();
ByteBuffer readings =
ByteBuffer.allocate((int) inSize);
inChannel.read(readings, 0);
for (int i = 0; readings.remaining() >
0; i++)
System.out.print(readings.get() + ” “);

A variant read() method, read(ByteBuffer, int, int), fills a portion of a buffer with data from a Channel, beginning at the position indicated by the second argument. The third argument specifies the number of bytes to read.

A Channel also has several write() methods to send data from a ByteBuffer. The write(ByteBuffer) method sends all of a buffer’s remaining bytes, beginning at the current position, over the Channel. The write(ByteBuffer, int, int) method sends a portion of a buffer, beginning at the offset indicated by the second argument and extending for the number of bytes indicated by the third argument.

Continuing our example code, the following code snippet sends the contents of the readings buffer over a new File Channel:

FileOutputStream opData =
new FileOutputStream(“output.dat”);
FileChannel opChannel =


Like FileInputStream.read() and FileOutputStream .write(), reading and writing data over a channel requires that IOException be caught or passed on with throws. Listing One shows a complete working program that “copies” a file using Channels.

Listing One: “Copy” a file using stream and channels

import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.ByteBuffer;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.FileNotFoundException;

public class NioExample {
public static void main(String[] args) \
throws IOException, FileNotFoundException {
FileInputStream inData = new FileInputStream(“input.dat”);
FileChannel inChannel = inData.getChannel();
long inSize = inChannel.size();
ByteBuffer readings = ByteBuffer.allocate((int) inSize);
inChannel.read(readings, 0);
for (int i = 0; readings.remaining() > 0; i++) {
System.out.print(readings.get() + ” “);

FileOutputStream opData = new FileOutputStream(“output.dat”);
FileChannel opChannel = opData.getChannel();


No More Blocking

As mentioned above, the java.nio.channels package also includes socket channels, which are used to send and receive data over a network. Unlike FileChannel, you can create socket channels directly. The really cool thing about socket channels? They support non-blocking input and output.

Blocking, once the bane of Java client and server programmers, occurs when a statement must executive and finish before anything else can happen in a program. Until Java 1.4, all socket programming caused blocking — and lots of headaches for programmers. Because numerous things can go wrong, it can be cumbersome for networking code to stop dead in its tracks while a statement is executed. A server can go offline, a connection can break, or a read operation can hang forever while it waits for something to happen.

For example, consider the example of an RSS aggregator that reads XML data from an RSS feed over an HTTP connection, buffering the data as it arrives. It’s possible for the RSS aggregator to block waiting for a buffer to be filled even though no more data remains to be sent. The block can make it appear as if the application has halted.

Non-blocking I/O lets an application continue even though a read or write operation is in process. To use non-blocking input and output, you must work with Channel instead of Stream.

A Finger Server

Last month, we created a finger client using the java.nio classes. Recall that the finger protocol, an old-school method of telling people about yourself, serves up the text in a user’s .plan file to anyone who requests it. For examples, visit the GameFinger Web site at http://finger.planetquake.com.

To try out non-blocking sockets, let’s create the other side of the finger protocol: a simple finger server that connects to clients with non-blocking sockets. Listing Two shows the complete source code for NioFingerServer, a server that uses a non-blocking socket channel to wait for incoming connections from finger clients.

Listing Two: A finger server using non-blocking sockets – Part 1

1 // Code requires J2SE 1.4
2 import java.io.*;
3 import java.net.*;
4 import java.nio.*;
5 import java.nio.channels.*;
6 import java.util.*;
8 public class NioFingerServer {
9 public NioFingerServer() {
10 try {
11 // Create a non-blocking server socket channel
12 ServerSocketChannel sockChannel = ServerSocketChannel.open();
13 sockChannel.configureBlocking(false);
15 InetSocketAddress server = new InetSocketAddress (“localhost”, 79);
16 ServerSocket socket = sockChannel.socket();
18 socket.bind(server);
20 // Create the selector and register it on the channel
21 Selector selector = Selector.open();
23 sockChannel.register (selector, SelectionKey.OP_ACCEPT);
25 // Loop forever, looking for client connections
26 while (true) {
27 // Wait for a connection
28 selector.select();
30 // Get list of selection keys with pending events
31 Set keys = selector.selectedKeys();
32 Iterator it = keys.iterator();
34 // Handle each key
35 while (it.hasNext()) {
37 // Get the key and remove it from the iteration
38 SelectionKey selKey = (SelectionKey) it.next();
40 it.remove();
41 if (selKey.isAcceptable()) {
43 // Create a socket connection with the client
44 ServerSocketChannel selChannel =
45 (ServerSocketChannel) selKey.channel();
46 ServerSocket selSocket = selChannel.socket();
47 Socket connection = selSocket.accept();
49 // Handle the finger request
50 handleRequest(connection);
51 connection.close();
52 }
53 }
54 }
55 } catch (IOException ioe) {
56 System.out.println(ioe.getMessage());
57 }
58 }
60 private void handleRequest(Socket connection) throws IOException {
62 // Set up input and output
63 InputStreamReader isr = new InputStreamReader (connection.getInputStream());
64 BufferedReader is = new BufferedReader(isr);
65 PrintWriter pw = new PrintWriter(new
66 BufferedOutputStream (connection.getOutputStream()),
67 false);
69 // Output server greeting
70 pw.println(“Nio Finger Server”);
71 pw.flush();
73 // Handle user input
74 String outLine = null;
75 String inLine = is.readLine();
77 if (inLine.length() > 0) {
78 outLine = inLine;
79 }
80 readPlan(outLine, pw);
82 // Clean up
83 pw.flush();
84 pw.close();
85 is.close();
86 }
88 private void readPlan (String userName, PrintWriter pw) {
89 try {
90 FileReader file = new FileReader (userName + “.plan”);
91 BufferedReader buff = new BufferedReader(file);
92 boolean eof = false;
94 pw.println(“\nUser name: ” + userName + “\n”);
96 while (!eof) {
97 String line = buff.readLine();
99 if (line == null)
100 eof = true;
101 else
102 pw.println(line);
103 }
105 buff.close();
106 } catch (IOException e) {
107 pw.println(“User ” + userName + ” not found.”);
108 }
109 }
111 public static void main(String[] arguments) {
112 NioFingerServer nio = new NioFingerServer();
113 }
114 }

On line 12, a new ServerSocketChannel is instantiated by calling the class method ServerSocketChannel.open(). The channel’s configureBlocking(boolean) method controls whether the channel blocks (if the argument is true) or not (false). Line 13 chooses non-blocking.

A ServerSocketChannel, unlike other channels, only makes connections. To send and receive any data over that channel, you must also create a server socket and bind it to an Internet address and port.

This sequence is shown in lines 15-18 (that Net code should look very famliar):

  • The InetSocketAddress class, part of the java .net package, represents an Internet address. To create an Internet socket address for a given host and port, call the constructor InetSocketAddress(String, int), with the hostname and port number. Line 15 uses localhost and 79 for hostname and port, respectively. (Line 15 is just one way to create an InetSocketAddress; see java.net for many other technique, including by numeric IP address.)

  • Line 16 creates a socket by calling the channel’s socket() method.

  • Finally, the Internet address must be bound to the server socket. This is accomplished with the socket’s bind(InetAddress) method, shown in Line 18.

If the channel was configured to be blocking, you could call the accept() method of the server socket to wait for a client connection. However, a non-blocking socket keeps track of incoming connection requests and other networking events with the use of a special listening object called a selector.

A selector, represented by the Selector class in the java.nio.channels package, can monitor several kinds of networking socket channels: clients (SocketChannel), servers (ServerSocketChannel), datagrams (DataGramChannel), and pipes (Pipe.SourceChannel and Pipe .SinkChannel). One selector can also monitor several channels at the same time.

A selector is instantiated by calling the class method Selector.open(). The selector only monitors events it’s been configured to monitor, which is accomplished by calling a socket channel’s register(Selector, int) or register(Selector, int, Object) methods.

The first two arguments to register() are the selector and an integer value that represents the kind of events being monitored, called selection keys. If there’s a third argument, the specified object will be delivered along with the key when a monitored event occurs.

Though you can use an integer literal as the second argument, it’s easier to make use of one or more class variables in the SelectionKey class. There’s SelectionKey.OP_CONNECT to monitor connections, SelectionKey.OP_READ to monitor channel read attempts, and SelectionKey .OP_WRITE to monitor channel write attempts. These “flags” are cumulative, so you can add two or three together to monitor more than one kind of event.

For example, the following code creates a selector to monitor a socket channel called wire for inbound connections and reads:

Selector tor = Selector.open();
channel.register(tor, SelectionKey.OP_READ +

The finger server only monitors incoming connections, as shown in lines 21 and 23.

A Selector has two methods that check for monitored selection keys: select(), which blocks until a key is triggered, and select(long), which waits the specified number of milliseconds for a keys before giving up. Both select() methods return an integer, which will either be the number of events that have taken place or 0, in cases where select(long) was called and no events took place in the specified time.

After one or more keys has been triggered, the selector’s selectedKeys() method returns the keys as a set, which you can traverse by using an iterator (the Set and Iterator classes of the java.util package). Each key is retrieved from the set by calling the iterator’s next() method and casting the result as a SelectionKey object. After a key has been retrieved, it should be removed from the set by calling the iterator’s remove() method.

The following code waits for one or more keys to be triggered and iterates through the keys:

Set keys = selector.selectedKeys();
Iterator it = keys.iterator();
while (it.hasNext()) {
SelectionKey selKey = (SelectionKey)it.next();

Similar code appears in Listing Two between lines 28 and 40.

There are three boolean methods in the SelectionKey class that identify the key in a server: isAcceptable(), isReadable(), and isWriteable(). Each method returns true if the key is that kind of event.

The key’s own channel() method identifies the socket channel where key was triggered.

For the finger server, this channel is used to create a server socket, which is used in turn to create a socket connection:

ServerSocketChannel selChannel =
(ServerSocketChannel) selKey.channel();
ServerSocket selSocket = selSocket.socket();
Socket connection = selSocket.accept();

This call to the accept() method blocks, waiting for the connection between the client and server to negotiate a connection. This socket can be used with reader and writer classes in the java.io package to exchange data.

All of the new networking techniques in the NioFingerServer application are contained in its constructor method. The handleRequest() and readPlan() methods use traditional Java socket programming techniques, making use of the socket that represents the connection between the finger server and a client.

For simplicity, this finger server keeps user .plan files in text files with names of the form username.plan, such as linus.plan, lucy.plan, or schroeder.plan.

To run this server, create one or more of these text files in the same folder as NioFingerServer.class, then run the server as root.

# echo “Protect my blanket.” > linus.plan
# echo “Trick Charlie Brown.” > lucy.plan
# echo “Play the piano.” > schroeder.plan
# javac NioFingerServer.java
# java -cp .:$CLASSPATH NioFingerServer

You can connect to this server using last month’s NioFinger client application (available online at http://www.linux-mag.com/downloads/2002-11/java/NioFinger.java) or use a telnet client to connect to localhost on port 79.

% telnet localhost 79
Connected to localhost.
Escape character is ‘^]’.
Nio Finger Server

User name: linus

Protect my blanket.
Connection closed by foreign host.

Clients and Sockets

Client programming using a socket channel uses many of the same techniques as server programming, with a few exceptions:

  • The SocketChannel class is used instead of ServerSocket.

  • The channel’s open() method opens the channel, and connect() attempts to make a connection to a server.

  • A socket channel can be registered with a Selector with the SelectionKey.OP_CONNECT value.

  • A selection key’s isConnectible() method identifies a connection to a server.

If a socket client’s channel is not blocking, any attempt to use the channel should be preceded by code that ensures that the connection has been fully established.

For instance, the following code could be used in a client before making use of a socket channel associated with a key named clientKey:

// If the connection is valid, then proceed
if (clientKey.isConnectable()) {
if (clientChannel.isConnectionPending()) {

The call to finishConnect() blocks until a connection to the server has been completed.

Stay Tuned

The NioFingerServer application can handle something as simple as finger requests, but more robust servers would make use of threads so that each server connection does not have the potential to grind to a screeching halt in a blocking call. Server socket channels are thread-safe, preventing two threads from calling accept() at the same time.

Another kind of network programming is in the .plan for next month’s Java Matters: we’ll take a look at Velocity, the open source template creation engine that separates the presentation of a Web application from the programming required to create it.

Rogers Cadenhead is a Web application developer and the coauthor of Teach Yourself Java 2 in 21 Days, Third Edition from Sams Publishing. To contact Cadenhead, visit his weblog at http://workbench.cadenhead.info. The source code used in this column can be downloaded in its entirety from Linux Magazine’s Web sit http://www.linux-mag.com/downloads/2002-11/java.

Comments are closed.