// Fig. 18.X: DeitelMessengerNonBlockingServer.java // Set up a nonblocking chatServer that will receive a connection from a // client and echo client's message to all connected clients. package com.deitel.messenger.sockets.server; import java.io.*; import java.nio.*; import java.nio.channels.*; import java.nio.channels.spi.*; import java.nio.charset.*; import java.net.*; import java.util.*; import java.awt.event.*; import javax.swing.*; public class DeitelMessengerNonBlockingServer extends JFrame { private ServerSocketChannel serverSocketChannel; private Selector selector; private Vector sockets = new Vector(); private int counter = 0; private JTextArea displayArea; private Charset charSet; private ByteBuffer writeBuffer; private ByteBuffer readBuffer = ByteBuffer.allocate( 512 ); public DeitelMessengerNonBlockingServer() { super( "DeitelMessenger Server" ); displayArea = new JTextArea(); getContentPane().add( new JScrollPane( displayArea ) ); setSize( 200, 300 ); setVisible( true ); // close server socket channel and selector when closing window addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent windowEvent ) { // close server socket channel and selector try { serverSocketChannel.close(); selector.close(); } catch( IOException ioException ) { ioException.printStackTrace(); } finally { System.exit( 0 ); } } } // end inner class WindowAdapter ); // end addWindowListener } // end constructor // set up and run server public void runServer() { // set up server to receive connections; process connections try { // specify the char set used to encode/decode messages charSet = Charset.forName( "UTF-8" ); // create a ServerSocketChannel. serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind( new InetSocketAddress( 12345 ) ); serverSocketChannel.configureBlocking( false ); // wait for a connection. getConnection(); } // end try // process problems with I/O catch ( Exception ioException ) { ioException.printStackTrace(); } } // end method runServer // wait for connection to arrive, then display connection info private void getConnection() throws Exception { // Selector for incoming requests selector = SelectorProvider.provider().openSelector(); serverSocketChannel.register( selector, SelectionKey.OP_ACCEPT, null ); // process incoming requests while ( selector.select() > 0 ) { // get channels ready for i/o Set readyKeys = selector.selectedKeys(); Iterator iterator = readyKeys.iterator(); // for each ready channel, process request while ( iterator.hasNext() ) { SelectionKey key = ( SelectionKey )iterator.next(); iterator.remove(); if ( key.isAcceptable() ) { // ready for connection // create connection ServerSocketChannel nextReady = ( ServerSocketChannel ) key.channel(); SocketChannel socketChannel = nextReady.accept(); if ( socketChannel != null ) { socketChannel.configureBlocking( false ); sockets.add( socketChannel.socket() ); counter++; SwingUtilities.invokeLater( new Runnable() { public void run() { displayArea.append( "\nConnection with Client " + counter ); } } ); // register read operation to socketChannel SelectionKey readKey = socketChannel.register( selector, SelectionKey.OP_READ, null ); } // end if socketChannel != null } // end if key.isAcceptable else if ( key.isReadable() ) { // ready for read // get socketChannel ready for read SocketChannel socketChannel = ( SocketChannel ) key.channel(); readMessage( socketChannel ); } } // end processing each channel } // end processing incoming requests } // end method getConnection // send message to client private void writeMessage( String message ) throws IOException { Socket socket; SocketChannel socketChannel; // echo message back to all connected clients for ( int i = 0; i < sockets.size(); i++ ) { socket = ( Socket ) sockets.elementAt( i ); socketChannel = socket.getChannel(); // send message to client try { // convert message to bytes in charSet writeBuffer = charSet.encode( message ); // write message to socketChannel socketChannel.write( writeBuffer ); } // process problems sending object catch ( IOException ioException ) { ioException.printStackTrace(); socketChannel.close(); sockets.remove( socket ); } } // end for } // end method writeMessage // read message from client private void readMessage( SocketChannel socketChannel ) throws IOException { // read message try { if ( socketChannel.isOpen() ) { readBuffer.clear(); socketChannel.read( readBuffer ); readBuffer.flip(); CharBuffer charMessage = charSet.decode( readBuffer ); String message = charMessage.toString().trim(); // remove and close the connection when client disconnects if ( message.indexOf( "Disconnect" ) >= 0 ) { sockets.remove( socketChannel.socket() ); socketChannel.close(); } else writeMessage( message ); } // end if } // end try catch ( IOException ioException ) { ioException.printStackTrace(); sockets.remove( socketChannel.socket() ); socketChannel.close(); } } // end method readMessage public static void main( String args[] ) { DeitelMessengerNonBlockingServer application = new DeitelMessengerNonBlockingServer(); application.runServer(); } } // end class DeitelMessengerNonBlockingServer /************************************************************************** * (C) Copyright 1992-2003 by Deitel & Associates, Inc. and * * Prentice Hall. All Rights Reserved. * * * * DISCLAIMER: The authors and publisher of this book have used their * * best efforts in preparing the book. These efforts include the * * development, research, and testing of the theories and programs * * to determine their effectiveness. The authors and publisher make * * no warranty of any kind, expressed or implied, with regard to these * * programs or to the documentation contained in these books. The authors * * and publisher shall not be liable in any event for incidental or * * consequential damages in connection with, or arising out of, the * * furnishing, performance, or use of these programs. * *************************************************************************/