Java Reference
In-Depth Information
You may also want to make the ServerSocketChannel nonblocking. By default, this
accept() method blocks until there's an incoming connection, like the accept() meth‐
od of ServerSocket . To change this, simply call configureBlocking(false) before
calling accept() :
serverChannel . configureBlocking ( false );
A nonblocking accept() returns null almost immediately if there are no incoming
connections. Be sure to check for that or you'll get a nasty NullPointerException when
trying to use the socket.
There are now two open channels: a server channel and a client channel. Both need to
be processed. Both can run indefinitely. Furthermore, processing the server channel
will create more open client channels. In the traditional approach, you assign each con‐
nection a thread, and the number of threads climbs rapidly as clients connect. Instead,
in the new I/O API, you create a Selector that enables the program to iterate over all
the connections that are ready to be processed. To construct a new Selector , just call
the static Selector.open() factory method:
Selector selector = Selector . open ();
Next, you need to register each channel with the selector that monitors it using the
channel's register() method. When registering, specify the operation you're interested
in using a named constant from the SelectionKey class. For the server socket, the only
operation of interest is OP_ACCEPT; that is, is the server socket channel ready to accept
a new connection?
serverChannel . register ( selector , SelectionKey . OP_ACCEPT );
For the client channels, you want to know something a little different—specifically,
whether they're ready to have data written onto them. For this, use the OP_WRITE key:
SelectionKey key = clientChannel . register ( selector , SelectionKey . OP_WRITE );
Both register() methods return a SelectionKey object. However, you're only going
to need to use that key for the client channels, because there can be more than one of
them. Each SelectionKey has an attachment of arbitrary Object type. This is normally
used to hold an object that indicates the current state of the connection. In this case,
you can store the buffer that the channel writes onto the network. Once the buffer is
fully drained, you'll refill it. Fill an array with the data that will be copied into each buffer.
Rather than writing to the end of the buffer, and then rewinding to the beginning of the
buffer and writing again, it's easier just to start with two sequential copies of the data so
every line is available as a contiguous sequence in the array:
byte [] rotation = new byte [ 95 * 2 ];
for ( byte i = ' ' ; i <= '~' ; i ++) {
rotation [ i - ' ' ] = i ;
rotation [ i + 95 - ' ' ] = i ;
}
Search WWH ::




Custom Search