Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Chapter 18 - Networking Outline 18.1 18.2 18.3 18.4 18.5 18.6 18.7 18.8 18.9 18.10 18.11 Introduction Manipulating URLs Reading a File on a Web Server Establishing a Simple Server Using Stream Sockets Establishing a Simple Client Using Stream Sockets Client/Server Interaction with Stream Socket Connections Connectionless Client/Server Interaction with Datagrams Client/Server Tic-Tac-Toe Using a Multithreaded Server Security and the Network DeitelMessenger Chat Server and Client 18.10.1 DeitelMessengerServer and Supporting Classes 18.10.2 DeitelMessenger Client and Supporting Classes NIO Networking Overview 2003 Prentice Hall, Inc. All rights reserved. Chapter 18 - Networking 18.12 Used (Optional) Discovering Design Patterns: Design Patterns in Packages java.io and java.net 18.12.1 Creational Design Patterns 18.12.2 Structural Design Patterns 18.12.3 Architectural Patterns 18.12.4 Conclusion 2003 Prentice Hall, Inc. All rights reserved. 18.1 Introduction • Networking package is java.net – Socket-based communications • Applications view networking as streams of data • Connection-based protocol • Uses TCP (Transmission Control Protocol) – Packet-based communications • Individual packets transmitted • Connectionless service • Uses UDP (User Datagram Protocol) 2003 Prentice Hall, Inc. All rights reserved. 18.2 Manipulating URLs • HyperText Transfer Protocol (HTTP) – Uses URIs (Uniform Resource Identifiers) to locate data • URIs frequently called URLs (Uniform Resource Locators) • Refer to files, directories and complex objects 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <html> <title>Site Selector</title> <body> <applet code = "SiteSelector.class" width = "300" height = "75"> <param name = "title0" value = "Java Home Page"> <param name = "location0" value = "http://java.sun.com/"> <param name = "title1" value = "Deitel"> <param name = "location1" value = "http://www.deitel.com/"> <param name = "title2" value = "JGuru"> <param name = "location2" value = "http://www.jGuru.com/"> <param name = "title3" value = "JavaWorld"> <param name = "location3" value = "http://www.javaworld.com/"> </applet> </body> </html> Outline SiteSelector.htm l Declare param tags Lines 5-12 for the applet 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // Fig. 18.2: SiteSelector.java // This program uses a button to load a document from a URL. import java.net.*; import java.util.*; import java.awt.*; import java.applet.AppletContext; import javax.swing.*; import javax.swing.event.*; public class SiteSelector extends JApplet { private HashMap sites; // site names and URLs private Vector siteNames; // site names private JList siteChooser; // list of sites to choose from Outline SiteSelector.ja va Lines 19-20 Create HashMap and Vector objects // read HTML parameters and set up GUI public void init() { // create HashMap and Vector sites = new HashMap(); siteNames = new Vector(); // obtain parameters from HTML document getSitesFromHTMLParameters(); 2003 Prentice Hall, Inc. All rights reserved. 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 // create GUI components and layout interface Container container = getContentPane(); container.add( new JLabel( "Choose a site to browse" ), BorderLayout.NORTH ); siteChooser = new JList( siteNames ); siteChooser.addListSelectionListener( Outline SiteSelector.ja va Line 36 new ListSelectionListener() { // go to site user selected public void valueChanged( ListSelectionEvent event ) { // get selected site name Object object = siteChooser.getSelectedValue(); // use site name to locate corresponding URL URL newDocument = ( URL ) sites.get( object ); Line 42 MethodLine 48 valueChanged goes to the selected Web site Create the document // get reference to applet container AppletContext browser = getAppletContext(); // tell applet container to change pages browser.showDocument( newDocument ); } Show the document in the browser 2003 Prentice Hall, Inc. All rights reserved. 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 } // end inner class Outline ); // end call to addListSelectionListener container.add( new JScrollPane( siteChooser ), BorderLayout.CENTER ); SiteSelector.ja va } // end method init Line 68 // obtain parameters from HTML document private void getSitesFromHTMLParameters() { // look for applet parameters in HTML document and add to HashMap String title, location; URL url; int counter = 0; Line 74 Get Web site title title = getParameter( "title" + counter ); // get first site title // loop until no more parameters in HTML document while ( title != null ) { // obtain site location location = getParameter( "location" + counter ); Get Web site location 2003 Prentice Hall, Inc. All rights reserved. 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 // place title/URL in HashMap try { url = new URL( location ); sites.put( title, url ); siteNames.add( title ); } and title in Vector // convert location to URL // put title/URL in HashMap // put title in Vector // process invalid URL format catch ( MalformedURLException urlException ) { urlException.printStackTrace(); } ++counter; title = getParameter( "title" + counter ); // get next site } // end while Outline SiteSelector.ja Create URL of va location Add URL Line 78 to HashMap Line title 79 Add to Vector Line 80 Get next title from title HTMLLine document 89 } // end method getSitesFromHTMLParameters } // end class SiteSelector 2003 Prentice Hall, Inc. All rights reserved. Outline SiteSelector.ja va 2003 Prentice Hall, Inc. All rights reserved. 18.3 Reading a File on a Web Server • Swing GUI component JEditorPane – Can display simple text and HTML formatted text – Can be used as a simple Web browser • Retrieves files from a Web server at a given URI 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // Fig. 18.3: ReadServerFile.java // Use a JEditorPane to display the contents of a file on a Web server. import java.awt.*; import java.awt.event.*; import java.net.*; import java.io.*; import javax.swing.*; import javax.swing.event.*; public class ReadServerFile extends JFrame { private JTextField enterField; private JEditorPane contentsArea; // set up GUI public ReadServerFile() { super( "Simple Web Browser" ); Outline ReadServerFile. java Line 12 File displayed in JEditorPane Container container = getContentPane(); // create enterField and register its listener enterField = new JTextField( "Enter file URL here" ); enterField.addActionListener( new ActionListener() { 2003 Prentice Hall, Inc. All rights reserved. 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 Outline // get document specified by user public void actionPerformed( ActionEvent event ) { getThePage( event.getActionCommand() ); } ReadServerFile. java } // end inner class Line 41 ); // end call to addActionListener container.add( enterField, BorderLayout.NORTH ); // create contentsArea and register HyperlinkEvent listener contentsArea = new JEditorPane(); contentsArea.setEditable( false ); contentsArea.addHyperlinkListener( new HyperlinkListener() { // if user clicked hyperlink, go to specified page public void hyperlinkUpdate( HyperlinkEvent event ) { if ( event.getEventType() == HyperlinkEvent.EventType.ACTIVATED ) getThePage( event.getURL().toString() ); } Linea45 Register HyperlinkListener Line 48 to handle HyperlinkEvents Line 49 Method hyperlinkUpdate called when hyperlink clicked Determine type of hyperlink Get URL of hyperlink and retrieve page 2003 Prentice Hall, Inc. All rights reserved. 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 } // end inner class Outline ); // end call to addHyperlinkListener container.add( new JScrollPane( contentsArea ), BorderLayout.CENTER ); setSize( 400, 300 ); setVisible( true ); ReadServerFile. java Line 68 } // end constructor ReadServerFile // load document private void getThePage( String location ) { // load document and display location try { contentsArea.setPage( location ); enterField.setText( location ); } catch ( IOException ioException ) { JOptionPane.showMessageDialog( this, "Error retrieving specified URL", "Bad URL", JOptionPane.ERROR_MESSAGE ); } Method setPage downloads document and displays it in JEditorPane } // end method getThePage 2003 Prentice Hall, Inc. All rights reserved. 78 79 80 81 82 83 84 85 public static void main( String args[] ) { ReadServerFile application = new ReadServerFile(); application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); } Outline ReadServerFile. java } // end class ReadServerFile 2003 Prentice Hall, Inc. All rights reserved. Outline ReadServerFile. java 2003 Prentice Hall, Inc. All rights reserved. 18.4 Establishing a Simple Server Using Stream Sockets • Five steps to create a simple server in Java – ServerSocket object • Registers an available port and a maximum number of clients – Each client connection handled with Socket object • Server blocks until client connects – Sending and receiving data • OutputStream to send and InputStream to receive data • Methods getInputStream and getOutputstream – Use on Socket object – Process phase • Server and Client communicate via streams – Close streams and connections 2003 Prentice Hall, Inc. All rights reserved. 18.5 Establishing a Simple Client Using Stream Sockets • Four steps to create a simple client in Java – – – – Create a Socket object for the client Obtain Socket’s InputStream and Outputstream Process information communicated Close streams and Socket 2003 Prentice Hall, Inc. All rights reserved. 18.6 Client/Server Interaction with Stream Socket Connections • Client/server chat application – Uses stream sockets as described in last two sections 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // Fig. 18.4: Server.java // Set up a Server that will receive a connection from a client, send // a string to the client, and close the connection. import java.io.*; import java.net.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Server extends JFrame { private JTextField enterField; private JTextArea displayArea; private ObjectOutputStream output; private ObjectInputStream input; private ServerSocket server; private Socket connection; private int counter = 1; Outline Server.java Lines 15-16 Listen on a ServerSocket; the connection is a Socket // set up GUI public Server() { super( "Server" ); Container container = getContentPane(); 2003 Prentice Hall, Inc. All rights reserved. 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 // create enterField and register listener enterField = new JTextField(); enterField.setEditable( false ); enterField.addActionListener( new ActionListener() { Outline Server.java // send message to client public void actionPerformed( ActionEvent event ) { sendData( event.getActionCommand() ); enterField.setText( "" ); } } ); container.add( enterField, BorderLayout.NORTH ); // create displayArea displayArea = new JTextArea(); container.add( new JScrollPane( displayArea ), BorderLayout.CENTER ); setSize( 300, 150 ); setVisible( true ); } // end Server constructor 2003 Prentice Hall, Inc. All rights reserved. 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 Outline // set up and run server public void runServer() { // set up server to receive connections; process connections try { // Step 1: Create a ServerSocket. server = new ServerSocket( 12345, 100 ); while ( true ) { Server.java Create Line 60 ServerSocket at port 12345 with queue of length 100 try { waitForConnection(); // Step 2: Wait for a connection. getStreams(); // Step 3: Get input & output streams. processConnection(); // Step 4: Process connection. } // process EOFException when client closes connection catch ( EOFException eofException ) { System.err.println( "Server terminated connection" ); } finally { closeConnection(); ++counter; } // Step 5: Close connection. 2003 Prentice Hall, Inc. All rights reserved. 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 } // end while } // end try // process problems with I/O catch ( IOException ioException ) { ioException.printStackTrace(); } Outline Server.java Line 95 Lines 96-97 } // end method runServer // wait for connection to arrive, then display connection info private void waitForConnection() throws IOException { displayMessage( "Waiting for connection\n" ); connection = server.accept(); // allow server to accept connection displayMessage( "Connection " + counter + " received from: " + connection.getInetAddress().getHostName() ); } Method accept waits for connection Output name of computer that connected // get streams to send and receive data private void getStreams() throws IOException { 2003 Prentice Hall, Inc. All rights reserved. 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 // set up output stream for objects output = new ObjectOutputStream( connection.getOutputStream() ); output.flush(); // flush output buffer to send header information // set up input stream for objects input = new ObjectInputStream( connection.getInputStream() ); displayMessage( "\nGot I/O streams\n" ); } Outline Server.java Method flush empties output Line 105 buffer and sends header information // process connection with client private void processConnection() throws IOException { // send connection successful message to client String message = "Connection successful"; sendData( message ); // enable enterField so server user can send messages setTextFieldEditable( true ); do { // process messages sent from client 2003 Prentice Hall, Inc. All rights reserved. 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 // read message and display it try { message = ( String ) input.readObject(); displayMessage( "\n" + message ); } // catch problems reading from client catch ( ClassNotFoundException classNotFoundException ) { displayMessage( "\nUnknown object type received" ); } Outline Server.java Read String from clientLines and display it 127-128 Line 141 } while ( !message.equals( "CLIENT>>> TERMINATE" ) ); } // end method processConnection // close streams and socket private void closeConnection() { displayMessage( "\nTerminating connection\n" ); setTextFieldEditable( false ); // disable enterField Method closeConnection closes streams and sockets try { output.close(); input.close(); connection.close(); } 2003 Prentice Hall, Inc. All rights reserved. 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 catch( IOException ioException ) { ioException.printStackTrace(); } } Outline Server.java // send message to client private void sendData( String message ) { // send object to client try { output.writeObject( "SERVER>>> " + message ); output.flush(); displayMessage( "\nSERVER>>> " + message ); } // process problems sending object catch ( IOException ioException ) { displayArea.append( "\nError writing object" ); } Line 162 Method flush empties output buffer and sends header information } // utility method called from other threads to manipulate // displayArea in the event-dispatch thread private void displayMessage( final String messageToDisplay ) { 2003 Prentice Hall, Inc. All rights reserved. 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 // display message from event-dispatch thread of execution SwingUtilities.invokeLater( new Runnable() { // inner class to ensure GUI updates properly public void run() // updates displayArea { displayArea.append( messageToDisplay ); displayArea.setCaretPosition( displayArea.getText().length() ); } } Outline Server.java // end inner class ); // end call to SwingUtilities.invokeLater } // utility method called from other threads to manipulate // enterField in the event-dispatch thread private void setTextFieldEditable( final boolean editable ) { // display message from event-dispatch thread of execution SwingUtilities.invokeLater( new Runnable() { // inner class to ensure GUI updates properly 2003 Prentice Hall, Inc. All rights reserved. 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 } public void run() // sets enterField's editability { enterField.setEditable( editable ); } } Outline Server.java // end inner class ); // end call to SwingUtilities.invokeLater } public static void main( String args[] ) { Server application = new Server(); application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); application.runServer(); } // end class Server 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 Outline // Fig. 18.5: Client.java // Client that reads and displays information sent from a Server. import java.io.*; import java.net.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Client extends JFrame { private JTextField enterField; private JTextArea displayArea; private ObjectOutputStream output; private ObjectInputStream input; private String message = ""; private String chatServer; private Socket client; Client.java Line 16 The client is a Socket // initialize chatServer and set up GUI public Client( String host ) { super( "Client" ); chatServer = host; // set server to which this client connects Container container = getContentPane(); 2003 Prentice Hall, Inc. All rights reserved. 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 // create enterField and register listener enterField = new JTextField(); enterField.setEditable( false ); enterField.addActionListener( new ActionListener() { Outline Client.java // send message to server public void actionPerformed( ActionEvent event ) { sendData( event.getActionCommand() ); enterField.setText( "" ); } } ); container.add( enterField, BorderLayout.NORTH ); // create displayArea displayArea = new JTextArea(); container.add( new JScrollPane( displayArea ), BorderLayout.CENTER ); setSize( 300, 150 ); setVisible( true ); 2003 Prentice Hall, Inc. All rights reserved. 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 } // end Client constructor // connect to server and process messages from server private void runClient() { // connect to server, get streams, process connection try { connectToServer(); // Step 1: Create a Socket to make connection getStreams(); // Step 2: Get the input and output streams processConnection(); // Step 3: Process connection } Outline Client.java // server closed connection catch ( EOFException eofException ) { System.err.println( "Client terminated connection" ); } // process problems communicating with server catch ( IOException ioException ) { ioException.printStackTrace(); } finally { closeConnection(); // Step 4: Close connection } 2003 Prentice Hall, Inc. All rights reserved. 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 } // end method runClient // connect to server private void connectToServer() throws IOException { displayMessage( "Attempting connection\n" ); // create Socket to make connection to server client = new Socket( InetAddress.getByName( chatServer ), 12345 ); // display connection information displayMessage( "Connected to: " + client.getInetAddress().getHostName() ); } // get streams to send and receive data private void getStreams() throws IOException { // set up output stream for objects output = new ObjectOutputStream( client.getOutputStream() ); output.flush(); // flush output buffer to send header information // set up input stream for objects input = new ObjectInputStream( client.getInputStream() ); Outline Client.java Line 86 Lines 89-90 Create client Linesa97 and that 101 will connect with port 12345 on the server Notify the user that we have connected Get the streams to send and receive data 2003 Prentice Hall, Inc. All rights reserved. 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 displayMessage( "\nGot I/O streams\n" ); Outline } // process connection with server private void processConnection() throws IOException { // enable enterField so client user can send messages setTextFieldEditable( true ); Client.java Line 117 do { // process messages sent from server // read message and display it try { message = ( String ) input.readObject(); displayMessage( "\n" + message ); } // catch problems reading from server catch ( ClassNotFoundException classNotFoundException ) { displayMessage( "\nUnknown object type received" ); } Read String from client and display it } while ( !message.equals( "SERVER>>> TERMINATE" ) ); } // end method processConnection 2003 Prentice Hall, Inc. All rights reserved. 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 // close streams and socket private void closeConnection() { displayMessage( "\nClosing connection" ); setTextFieldEditable( false ); // disable enterField try { output.close(); input.close(); client.close(); } catch( IOException ioException ) { ioException.printStackTrace(); } Outline Client.java Method Line 130 closeConnection closes streams and Line 151 sockets } // send message to server private void sendData( String message ) { // send object to server try { output.writeObject( "CLIENT>>> " + message ); output.flush(); displayMessage( "\nCLIENT>>> " + message ); } Method flush empties output buffer and sends header information 2003 Prentice Hall, Inc. All rights reserved. 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 // process problems sending object catch ( IOException ioException ) { displayArea.append( "\nError writing object" ); } Outline Client.java } // utility method called from other threads to manipulate // displayArea in the event-dispatch thread private void displayMessage( final String messageToDisplay ) { // display message from GUI thread of execution SwingUtilities.invokeLater( new Runnable() { // inner class to ensure GUI updates properly public void run() // updates displayArea { displayArea.append( messageToDisplay ); displayArea.setCaretPosition( displayArea.getText().length() ); } } // end inner class ); // end call to SwingUtilities.invokeLater } 2003 Prentice Hall, Inc. All rights reserved. 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 // utility method called from other threads to manipulate // enterField in the event-dispatch thread private void setTextFieldEditable( final boolean editable ) { // display message from GUI thread of execution SwingUtilities.invokeLater( new Runnable() { // inner class to ensure GUI updates properly Outline Client.java public void run() // sets enterField's editability { enterField.setEditable( editable ); } } // end inner class ); // end call to SwingUtilities.invokeLater } public static void main( String args[] ) { Client application; 2003 Prentice Hall, Inc. All rights reserved. 203 if ( args.length == 0 ) 204 application = new Client( "127.0.0.1" ); 205 else 206 application = new Client( args[ 0 ] ); 207 208 application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); 209 application.runClient(); 210 } 211 212 } // end class Client Outline Client.java Create a client to Line 204 connect to the localhost Connect to a host Line 206 supplied by the user 2003 Prentice Hall, Inc. All rights reserved. Outline Client.java 2003 Prentice Hall, Inc. All rights reserved. 18.7 Connectionless Client/Server Interaction with Datagrams • Connectionless transmission with datagrams – – – – No connection maintained with other computer Break message into equal sized pieces and send as packets Message arrive in order, out of order or not at all Receiver puts messages in order and reads them 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 // Fig. 18.6: Server.java // Server that receives and sends packets from/to a client. import java.io.*; import java.net.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Server extends JFrame { private JTextArea displayArea; private DatagramSocket socket; Outline Server.java Line 11 Line 26 Use a DatagramSocket as our server // set up GUI and DatagramSocket public Server() { super( "Server" ); displayArea = new JTextArea(); getContentPane().add( new JScrollPane( displayArea ), BorderLayout.CENTER ); setSize( 400, 300 ); setVisible( true ); // create DatagramSocket for sending and receiving packets try { socket = new DatagramSocket( 5000 ); } The socket will listen on port 5000 2003 Prentice Hall, Inc. All rights reserved. 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 Outline // process problems creating DatagramSocket catch( SocketException socketException ) { socketException.printStackTrace(); System.exit( 1 ); } Server.java Lines 47-48 } // end Server constructor Line 50 // wait for packets to arrive, display data and echo packet to client private void waitForPackets() { while ( true ) { // loop forever // receive packet, display contents, return copy to client try { // set up packet byte data[] = new byte[ 100 ]; DatagramPacket receivePacket = new DatagramPacket( data, data.length ); socket.receive( receivePacket ); // wait for packet Create a DatagramPacket to store received information Method receive blocks until a packet is received 2003 Prentice Hall, Inc. All rights reserved. 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 // display information from received packet displayMessage( "\nPacket received:" + "\nFrom host: " + receivePacket.getAddress() + "\nHost port: " + receivePacket.getPort() + "\nLength: " + receivePacket.getLength() + "\nContaining:\n\t" + new String( receivePacket.getData(), 0, receivePacket.getLength() ) ); sendPacketToClient( receivePacket ); // send packet to client } // process problems manipulating packet catch( IOException ioException ) { displayMessage( ioException.toString() + "\n" ); ioException.printStackTrace(); } } // end while } // end method waitForPackets Outline Method Server.java getAddress returns Line 54 name of computer that sent Method getPort Line packet 55 returns the port the packet Linecame 56 through Method getLength Line 57 returns the length of the message sent Method getData returns a byte array containing the sent data // echo packet to client private void sendPacketToClient( DatagramPacket receivePacket ) throws IOException { 2003 Prentice Hall, Inc. All rights reserved. 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 Outline displayMessage( "\n\nEcho data to client..." ); // create packet to send DatagramPacket sendPacket = new DatagramPacket( receivePacket.getData(), receivePacket.getLength(), receivePacket.getAddress(), receivePacket.getPort() ); Server.java Create packet to be sentLines 80-82 socket.send( sendPacket ); // send packet displayMessage( "Packet sent\n" ); } // utility method called from other threads to manipulate // displayArea in the event-dispatch thread private void displayMessage( final String messageToDisplay ) { // display message from event-dispatch thread of execution SwingUtilities.invokeLater( new Runnable() { // inner class to ensure GUI updates properly Line 84 Method send sends the packet over the network public void run() // updates displayArea { displayArea.append( messageToDisplay ); displayArea.setCaretPosition( displayArea.getText().length() ); } 2003 Prentice Hall, Inc. All rights reserved. 102 103 } // end inner class 104 105 ); // end call to SwingUtilities.invokeLater 106 } 107 108 public static void main( String args[] ) 109 { 110 Server application = new Server(); 111 application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); 112 application.waitForPackets(); 113 } 114 115 } // end class Server Outline Server.java 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // Fig. 18.7: Client.java // Client that sends and receives packets to/from a server. import java.io.*; import java.net.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Client extends JFrame { private JTextField enterField; private JTextArea displayArea; private DatagramSocket socket; // set up GUI and DatagramSocket public Client() { super( "Client" ); Outline Client.java Line 12 Use a DatagramSocket as our client Container container = getContentPane(); enterField = new JTextField( "Type message here" ); enterField.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent event ) { 2003 Prentice Hall, Inc. All rights reserved. 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 // create and send packet try { displayArea.append( "\nSending packet containing: " + event.getActionCommand() + "\n" ); // get message from textfield and convert to byte String message = event.getActionCommand(); byte data[] = message.getBytes(); Outline Client.java Convert the String array to a byte Linearray 33 Lines 36-37 // create sendPacket DatagramPacket sendPacket = new DatagramPacket( data, data.length, InetAddress.getLocalHost(), 5000 ); socket.send( sendPacket ); // send packet displayArea.append( "Packet sent\n" ); displayArea.setCaretPosition( displayArea.getText().length() ); } // process problems creating or sending packet catch ( IOException ioException ) { displayMessage( ioException.toString() + "\n" ); ioException.printStackTrace(); } Line 39 Create the DatagramPacket to send Method send sends the packet over the network 2003 Prentice Hall, Inc. All rights reserved. 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 } // end actionPerformed Outline } // end inner class ); // end call to addActionListener container.add( enterField, BorderLayout.NORTH ); Client.java Line 68 displayArea = new JTextArea(); container.add( new JScrollPane( displayArea ), BorderLayout.CENTER ); setSize( 400, 300 ); setVisible( true ); // create DatagramSocket for sending and receiving packets try { socket = new DatagramSocket(); } Create a DatagramSocket for sending and receiving packets // catch problems creating DatagramSocket catch( SocketException socketException ) { socketException.printStackTrace(); System.exit( 1 ); } 2003 Prentice Hall, Inc. All rights reserved. 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 } // end Client constructor // wait for packets to arrive from Server, display packet contents private void waitForPackets() { while ( true ) { // loop forever // receive packet and display contents try { // set up packet byte data[] = new byte[ 100 ]; DatagramPacket receivePacket = new DatagramPacket( data, data.length ); socket.receive( receivePacket ); // wait for packet // display packet contents displayMessage( "\nPacket received:" + "\nFrom host: " + receivePacket.getAddress() + "\nHost port: " + receivePacket.getPort() + "\nLength: " + receivePacket.getLength() + "\nContaining:\n\t" + new String( receivePacket.getData(), 0, receivePacket.getLength() ) ); } Outline Client.java Create a DatagramPacket Lines to store89-90 received information Method receive Line 92 blocks until a packet is received Line 96 Method Line 97 getAddress returns Linename 98 of computer that sent Methodpacket getPort Line 99 returns the port the packet came through Method getLength returns the length of the message sent Method getData returns a byte array containing the sent data 2003 Prentice Hall, Inc. All rights reserved. 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 // process problems receiving or displaying packet catch( IOException exception ) { displayMessage( exception.toString() + "\n" ); exception.printStackTrace(); } Outline Client.java } // end while } // end method waitForPackets // utility method called from other threads to manipulate // displayArea in the event-dispatch thread private void displayMessage( final String messageToDisplay ) { // display message from event-dispatch thread of execution SwingUtilities.invokeLater( new Runnable() { // inner class to ensure GUI updates properly public void run() // updates displayArea { displayArea.append( messageToDisplay ); displayArea.setCaretPosition( displayArea.getText().length() ); } 2003 Prentice Hall, Inc. All rights reserved. 127 128 129 130 131 132 133 134 135 136 137 138 139 140 } } // end inner class ); // end call to SwingUtilities.invokeLater } Outline Client.java public static void main( String args[] ) { Client application = new Client(); application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); application.waitForPackets(); } // end class Client 2003 Prentice Hall, Inc. All rights reserved. 18.8 Client/Server Tic-Tac-Toe Using a Multithreaded Server • Multiple threads – Server uses one thread per player • Allow each player to play game independently 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // Fig. 18.8: TicTacToeServer.java // This class maintains a game of Tic-Tac-Toe for two client applets. import java.awt.*; import java.awt.event.*; import java.net.*; import java.io.*; import javax.swing.*; Outline TicTacToeServer .java public class TicTacToeServer extends JFrame { private char[] board; private JTextArea outputArea; private Player[] players; private ServerSocket server; private int currentPlayer; private final int PLAYER_X = 0, PLAYER_O = 1; private final char X_MARK = 'X', O_MARK = 'O'; // set up tic-tac-toe server and GUI that displays messages public TicTacToeServer() { super( "Tic-Tac-Toe Server" ); board = new char[ 9 ]; players = new Player[ 2 ]; currentPlayer = PLAYER_X; 2003 Prentice Hall, Inc. All rights reserved. 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 // set up ServerSocket try { server = new ServerSocket( 12345, 2 ); } // process problems creating ServerSocket catch( IOException ioException ) { ioException.printStackTrace(); System.exit( 1 ); } // set up JTextArea to display messages during execution outputArea = new JTextArea(); getContentPane().add( outputArea, BorderLayout.CENTER ); outputArea.setText( "Server awaiting connections\n" ); setSize( 300, 300 ); setVisible( true ); Outline Create ServerSocket to TicTacToeServer listen on .java port 12345 Line 29 Line 49 Method execute waits for two connections to start game } // end TicTacToeServer constructor // wait for two connections so game can be played public void execute() { 2003 Prentice Hall, Inc. All rights reserved. 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 // wait for each client to connect for ( int i = 0; i < players.length; i++ ) { // wait for connection, create Player, start thread try { players[ i ] = new Player( server.accept(), i ); players[ i ].start(); } // process problems receiving connection from client catch( IOException ioException ) { ioException.printStackTrace(); System.exit( 1 ); } Outline TicTacToeServer Block while waiting .java for each player Line 56 Call start method Line 57 to begin executing thread } // Player X is suspended until Player O connects. // Resume player X now. synchronized ( players[ PLAYER_X ] ) { players[ PLAYER_X ].setSuspended( false ); players[ PLAYER_X ].notify(); } } // end method execute 2003 Prentice Hall, Inc. All rights reserved. 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 // utility method called from other threads to manipulate // outputArea in the event-dispatch thread private void displayMessage( final String messageToDisplay ) { // display message from event-dispatch thread of execution SwingUtilities.invokeLater( new Runnable() { // inner class to ensure GUI updates properly Outline TicTacToeServer .java public void run() // updates outputArea { outputArea.append( messageToDisplay ); outputArea.setCaretPosition( outputArea.getText().length() ); } } // end inner class ); // end call to SwingUtilities.invokeLater } // Determine if a move is valid. This method is synchronized because // only one move can be made at a time. public synchronized boolean validateAndMove( int location, int player ) { boolean moveDone = false; 2003 Prentice Hall, Inc. All rights reserved. 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 // while not current player, must wait for turn while ( player != currentPlayer ) { // wait for turn try { wait(); } Outline TicTacToeServer .java // catch wait interruptions catch( InterruptedException interruptedException ) { interruptedException.printStackTrace(); } } // if location not occupied, make move if ( !isOccupied( location ) ) { // set move in board array board[ location ] = currentPlayer == PLAYER_X ? X_MARK : O_MARK; // change current player currentPlayer = ( currentPlayer + 1 ) % 2; // let new current player know that move occurred players[ currentPlayer ].otherPlayerMoved( location ); 2003 Prentice Hall, Inc. All rights reserved. 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 notify(); // tell waiting player to continue // tell player that made move that the move was valid return true; } Outline TicTacToeServer .java // tell player that made move that the move was not valid else return false; } // end method validateAndMove // determine whether location is occupied public boolean isOccupied( int location ) { if ( board[ location ] == X_MARK || board [ location ] == O_MARK ) return true; else return false; } // place code in this method to determine whether game over public boolean isGameOver() { return false; // this is left as an exercise } 2003 Prentice Hall, Inc. All rights reserved. 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 public static void main( String args[] ) { TicTacToeServer application = new TicTacToeServer(); application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); application.execute(); } Outline TicTacToeServer .java // private inner class Player manages each Player as a thread private class Player extends Thread { private Socket connection; private DataInputStream input; private DataOutputStream output; private int playerNumber; private char mark; protected boolean suspended = true; // set up Player thread public Player( Socket socket, int number ) { playerNumber = number; // specify player's mark mark = ( playerNumber == PLAYER_X ? X_MARK : O_MARK ); 2003 Prentice Hall, Inc. All rights reserved. 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 Outline connection = socket; // obtain streams from Socket try { input = new DataInputStream( connection.getInputStream() ); output = new DataOutputStream( connection.getOutputStream() ); } // process problems getting streams catch( IOException ioException ) { ioException.printStackTrace(); System.exit( 1 ); } TicTacToeServer .java Lines Get the183-184 streams to send and receive data Lines 200-201 } // end Player constructor // send message that other player moved public void otherPlayerMoved( int location ) { // send message indicating move try { output.writeUTF( "Opponent moved" ); output.writeInt( location ); } Send output notifying the other player of the move 2003 Prentice Hall, Inc. All rights reserved. 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 // process problems sending message catch ( IOException ioException ) { ioException.printStackTrace(); } } // control thread's execution public void run() { // send client message indicating its mark (X or O), // process messages from client try { displayMessage( "Player " + ( playerNumber == PLAYER_X ? X_MARK : O_MARK ) + " connected\n" ); output.writeChar( mark ); // send player's mark // send message indicating connection output.writeUTF( "Player " + ( playerNumber == PLAYER_X ? "X connected\n" : "O connected, please wait\n" ) ); Outline TicTacToeServer .java Line 219 Line 227 Send player’s mark Wait for other player // if player X, wait for another player to arrive if ( mark == X_MARK ) { output.writeUTF( "Waiting for another player" ); 2003 Prentice Hall, Inc. All rights reserved. 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 // wait for player O try { synchronized( this ) { while ( suspended ) wait(); } } Outline TicTacToeServer .java Line 244 // process interruptions while waiting catch ( InterruptedException exception ) { exception.printStackTrace(); } Line 251 Begin the game // send message that other player connected and // player X can make a move output.writeUTF( "Other player connected. Your move." ); } // while game not over while ( ! isGameOver() ) { // get move location from client int location = input.readInt(); Read a move 2003 Prentice Hall, Inc. All rights reserved. 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 // check for valid move if ( validateAndMove( location, playerNumber ) ) { displayMessage( "\nlocation: " + location ); output.writeUTF( "Valid move." ); } else output.writeUTF( "Invalid move, try again" ); } Outline TicTacToeServer Send message to .java client Line 256 connection.close(); // close connection to client } // end try // process problems communicating with client catch( IOException ioException ) { ioException.printStackTrace(); System.exit( 1 ); } } // end method run // set whether or not thread is suspended public void setSuspended( boolean status ) { suspended = status; } 2003 Prentice Hall, Inc. All rights reserved. 279 280 } // end class Player 281 282 } // end class TicTacToeServer Outline TicTacToeServer .java 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // Fig. 18.9: TicTacToeClient.java // Client that let a user play Tic-Tac-Toe with another across a network. import java.awt.*; import java.awt.event.*; import java.net.*; import java.io.*; import javax.swing.*; Outline TicTacToeClient .java public class TicTacToeClient extends JApplet implements Runnable { private JTextField idField; private JTextArea displayArea; private JPanel boardPanel, panel2; private Square board[][], currentSquare; private Socket connection; private DataInputStream input; private DataOutputStream output; private char myMark; private boolean myTurn; private final char X_MARK = 'X', O_MARK = 'O'; // Set up user-interface and board public void init() { Container container = getContentPane(); 2003 Prentice Hall, Inc. All rights reserved. 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 // set up JTextArea to display messages to user displayArea = new JTextArea( 4, 30 ); displayArea.setEditable( false ); container.add( new JScrollPane( displayArea ), BorderLayout.SOUTH ); // set up panel for squares in board boardPanel = new JPanel(); boardPanel.setLayout( new GridLayout( 3, 3, 0, 0 ) ); Outline TicTacToeClient .java // create board board = new Square[ 3 ][ 3 ]; // When creating a Square, the location argument to the constructor // is a value from 0 to 8 indicating the position of the Square on // the board. Values 0, 1, and 2 are the first row, values 3, 4, // and 5 are the second row. Values 6, 7, and 8 are the third row. for ( int row = 0; row < board.length; row++ ) { for ( int column = 0; column < board[ row ].length; column++ ) { // create Square board[ row ][ column ] = new Square( ' ', row * 3 + column ); boardPanel.add( board[ row ][ column ] ); } } 2003 Prentice Hall, Inc. All rights reserved. 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 // textfield to display player's mark idField = new JTextField(); idField.setEditable( false ); container.add( idField, BorderLayout.NORTH ); // set up panel to contain boardPanel (for layout purposes) panel2 = new JPanel(); panel2.add( boardPanel, BorderLayout.CENTER ); container.add( panel2, BorderLayout.CENTER ); } // end method init // Make connection to server and get associated streams. // Start separate thread to allow this applet to // continually update its output in textarea display. public void start() { // connect to server, get streams and start outputThread try { Outline TicTacToeClient .java Line 73 Lines 76-77 Connect to the server // make connection connection = new Socket( getCodeBase().getHost(), 12345 ); // get streams input = new DataInputStream( connection.getInputStream() ); output = new DataOutputStream( connection.getOutputStream() ); Get the streams to send and receive data 2003 Prentice Hall, Inc. All rights reserved. 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 Outline } // catch problems setting up connection and streams catch ( IOException ioException ) { ioException.printStackTrace(); } // create and start output thread Thread outputThread = new Thread( this ); outputThread.start(); TicTacToeClient .java Line 96 } // end method start // control thread that allows continuous update of displayArea public void run() { // get player's mark (X or O) try { myMark = input.readChar(); // display player ID in event-dispatch thread SwingUtilities.invokeLater( new Runnable() { public void run() { Read mark character from server 2003 Prentice Hall, Inc. All rights reserved. 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 idField.setText( "You are player \"" + myMark + "\"" ); } Outline } ); myTurn = ( myMark == X_MARK ? true : false ); // receive messages sent to client and output them while ( true ) { processMessage( input.readUTF() ); } } // end try TicTacToeClient .java Loop continually Line 111 Line 112 Read and process messages from server // process problems communicating with server catch ( IOException ioException ) { ioException.printStackTrace(); } } // end method run // process messages received by client private void processMessage( String message ) { 2003 Prentice Hall, Inc. All rights reserved. 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 // valid move occurred if ( message.equals( "Valid move." ) ) { displayMessage( "Valid move, please wait.\n" ); setMark( currentSquare, myMark ); } // invalid move occurred else if ( message.equals( "Invalid move, try again" ) ) { displayMessage( message + "\n" ); myTurn = true; } // opponent moved else if ( message.equals( "Opponent moved" ) ) { // get try { int int int move location and update board Outline TicTacToeClient If valid move, write .java message and set mark in square Line 128 Line 134 If invalid move, displayLine message 140 If opponent moves, set mark in square location = input.readInt(); row = location / 3; column = location % 3; setMark( board[ row ][ column ], ( myMark == X_MARK ? O_MARK : X_MARK ) ); displayMessage( "Opponent moved. Your turn.\n" ); myTurn = true; 2003 Prentice Hall, Inc. All rights reserved. 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 } // end try // process problems communicating with server catch ( IOException ioException ) { ioException.printStackTrace(); } Outline TicTacToeClient .java } // end else if // simply display message else displayMessage( message + "\n" ); } // end method processMessage // utility method called from other threads to manipulate // outputArea in the event-dispatch thread private void displayMessage( final String messageToDisplay ) { // display message from event-dispatch thread of execution SwingUtilities.invokeLater( new Runnable() { // inner class to ensure GUI updates properly 2003 Prentice Hall, Inc. All rights reserved. 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 public void run() // updates displayArea { displayArea.append( messageToDisplay ); displayArea.setCaretPosition( displayArea.getText().length() ); } } Outline TicTacToeClient .java // end inner class ); // end call to SwingUtilities.invokeLater } // utility method to set mark on board in event-dispatch thread private void setMark( final Square squareToMark, final char mark ) { SwingUtilities.invokeLater( new Runnable() { public void run() { squareToMark.setMark( mark ); } } ); } 2003 Prentice Hall, Inc. All rights reserved. 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 // send message to server indicating clicked square public void sendClickedSquare( int location ) { if ( myTurn ) { // send location to server try { output.writeInt( location ); myTurn = false; } // process problems communicating with server catch ( IOException ioException ) { ioException.printStackTrace(); } Outline TicTacToeClient .java Line 208 Send the move to the server } } // set current Square public void setCurrentSquare( Square square ) { currentSquare = square; } 2003 Prentice Hall, Inc. All rights reserved. 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 // private inner class for the squares on the board private class Square extends JPanel { private char mark; private int location; public Square( char squareMark, int squareLocation ) { mark = squareMark; location = squareLocation; Outline TicTacToeClient .java addMouseListener( new MouseAdapter() { public void mouseReleased( MouseEvent e ) { setCurrentSquare( Square.this ); sendClickedSquare( getSquareLocation() ); } } ); } // end Square constructor // return preferred size of Square public Dimension getPreferredSize() { 2003 Prentice Hall, Inc. All rights reserved. 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 return new Dimension( 30, 30 ); } // return minimum size of Square public Dimension getMinimumSize() { return getPreferredSize(); } Outline TicTacToeClient .java // set mark for Square public void setMark( char newMark ) { mark = newMark; repaint(); } // return Square location public int getSquareLocation() { return location; } // draw Square public void paintComponent( Graphics g ) { 2003 Prentice Hall, Inc. All rights reserved. 275 super.paintComponent( g ); 276 277 g.drawRect( 0, 0, 29, 29 ); 278 g.drawString( String.valueOf( mark ), 11, 20 ); 279 } 280 281 } // end inner-class Square 282 283 } // end class TicTacToeClient Outline TicTacToeClient .java 2003 Prentice Hall, Inc. All rights reserved. Outline TicTacToeClient .java 2003 Prentice Hall, Inc. All rights reserved. Outline TicTacToeClient .java 2003 Prentice Hall, Inc. All rights reserved. 18.9 Security and the Network • By default, applets cannot perform file processing • Applets often limited in machine access • Java Security API – Applets given more privileges if from trusted source 2003 Prentice Hall, Inc. All rights reserved. 18.10 DeitelMessenger Chat Server and Client • Chat rooms – Each user can post a message and read all other messages – Multicast • Send packets to groups of clients 2003 Prentice Hall, Inc. All rights reserved. 18.10.1 DeitelMessengerServer and Supporting Classes • DeitelMessengerServer – Online chat system – Classes: • DeitelMessengerServer – Clients connect to this server • Interface SocketMessengerConstants – Defines constants for port numbers • Interface MessageListener – Defines method for receiving new chat messages • Class ReceivingThread – Separate thread listens for messages from clients • Class MulticastSendingThread – Separate thread delivers outgoing messages to clients 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // Fig. 18.11: DeitelMessengerServer.java // DeitelMessengerServer is a multi-threaded, socket- and // packet-based chat server. package com.deitel.messenger.sockets.server; import java.util.*; import java.net.*; import java.io.*; Outline DeitelMessenger Server.java Line 13 import com.deitel.messenger.*; import com.deitel.messenger.sockets.*; public class DeitelMessengerServer implements MessageListener { // start chat server public void startServer() { // create server and manage new clients try { Implement the MessageListener interface // create ServerSocket for incoming connections ServerSocket serverSocket = new ServerSocket( SocketMessengerConstants.SERVER_PORT, 100 ); 2003 Prentice Hall, Inc. All rights reserved. 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 System.out.println( "Server listening on port " + SocketMessengerConstants.SERVER_PORT + " ..." ); // listen for clients constantly while ( true ) { // accept new client connection Socket clientSocket = serverSocket.accept(); Outline DeitelMessenger Server.java // create new ReceivingThread for receiving // messages from client new ReceivingThread( this, clientSocket ).start(); 32 InvokeLine method accept to wait for Linea36 and accept new client connection // print connection information System.out.println( "Connection received from: " + clientSocket.getInetAddress() ); Create and start a new ReceivingThread } // end while } // end try // handle exception creating server and connecting clients catch ( IOException ioException ) { ioException.printStackTrace(); } 2003 Prentice Hall, Inc. All rights reserved. 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 Outline } // end method startServer // when new message is received, broadcast message to clients public void messageReceived( String from, String message ) { // create String containing entire message String completeMessage = from + SocketMessengerConstants.MESSAGE_SEPARATOR + message; Method DeitelMessenger messageReceived Server.java broadcasts new messagesLine to clients 54 // create and start MulticastSendingThread to broadcast // new messages to all clients new MulticastSendingThread( completeMessage.getBytes() ).start(); Line 62 } public static void main ( String args[] ) { new DeitelMessengerServer().startServer(); } Create and start new MulticastSendingThread to send messages to all clients } // end class DeitelMessengerServer Server listening on port 5000 ... Connection received from: SEANSANTRY/XXX.XXX.XXX.XXX Connection received from: PJD/XXX.XXX.XXX.XXX 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 // Fig. 18.12: SocketMessengerConstants.java // SocketMessengerConstants declares constants for the port numbers // and multicast address in DeitelMessenger package com.deitel.messenger.sockets; public interface SocketMessengerConstants { // address for multicast datagrams public static final String MULTICAST_ADDRESS = "239.0.0.1"; // port for listening for multicast datagrams public static final int MULTICAST_LISTENING_PORT = 5555; // port for sending multicast datagrams public static final int MULTICAST_SENDING_PORT = 5554; // port for Socket connections to DeitelMessengerServer public static final int SERVER_PORT = 5000; // String that indicates disconnect public static final String DISCONNECT_STRING = "DISCONNECT"; // String that separates the user name from the message body public static final String MESSAGE_SEPARATOR = ">>>"; // message size (in bytes) public static final int MESSAGE_SIZE = 512; } Outline SocketMessenger Constants.java Line 9 Address to send multicast datagrams Line 12 Port listening for 15 multicast Line datagrams Port for sending Line 18 multicast datagrams Line 21 Port for socket connections Lineto 24server String that 27 indicatesLine disconnect String that separates user name and message Maximum message sizein2003 bytes Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 // Fig. 18.13: MessageListener.java // MessageListener is an interface for classes that wish to // receive new chat messages. package com.deitel.messenger; public interface MessageListener { // receive new chat message public void messageReceived( String from, String message ); } Outline MessageListener .java Method Line 9 messageReceived allows an implementing class to receive messages 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 // Fig. 18.14: ReceivingThread.java // ReceivingThread is a Thread that listens for messages from a // particular client and delivers messages to a MessageListener. package com.deitel.messenger.sockets.server; import java.io.*; import java.net.*; import java.util.StringTokenizer; Outline ReceivingThread .java import com.deitel.messenger.*; import com.deitel.messenger.sockets.*; public class ReceivingThread extends Thread { private BufferedReader input; private MessageListener messageListener; private boolean keepListening = true; // ReceivingThread constructor public ReceivingThread( MessageListener listener, Socket clientSocket ) { // invoke superclass constructor to name Thread super( "ReceivingThread: " + clientSocket ); // set listener to which new messages should be sent messageListener = listener; 2003 Prentice Hall, Inc. All rights reserved. 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 // set timeout for reading from clientSocket and create // BufferedReader for reading incoming messages try { clientSocket.setSoTimeout( 5000 ); input = new BufferedReader( new InputStreamReader( clientSocket.getInputStream() ) ); Outline ReceivingThread Attempt to read.java for five seconds Line 31 } // handle exception creating BufferedReader catch ( IOException ioException ) { ioException.printStackTrace(); } } // end ReceivingThread constructor // listen for new messages and deliver them to MessageListener public void run() { String message; // listen for messages until stopped while ( keepListening ) { 2003 Prentice Hall, Inc. All rights reserved. 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 // read message from BufferedReader try { message = input.readLine(); } Outline Read line of data from ReceivingThread client .java // handle exception if read times out catch ( InterruptedIOException interruptedIOException ) { // continue to next iteration to keep listening continue; } Line 54 An InterruptedException is thrown if the Line read times 58 out Lines 74-75 // handle exception reading message catch ( IOException ioException ) { ioException.printStackTrace(); break; } // ensure non-null message if ( message != null ) { Separate message into two tokens delimited by body Message_SEPARATOR // tokenize message to retrieve user name and message StringTokenizer tokenizer = new StringTokenizer( message, SocketMessengerConstants.MESSAGE_SEPARATOR ); 2003 Prentice Hall, Inc. All rights reserved. 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 // ignore messages that do not contain a user // name and message body if ( tokenizer.countTokens() == 2 ) // send message to MessageListener messageListener.messageReceived( tokenizer.nextToken(), // user name tokenizer.nextToken() ); // message body Outline ReceivingThread .java Lines 89-92 else // if disconnect message received, stop listening if ( message.equalsIgnoreCase( SocketMessengerConstants.MESSAGE_SEPARATOR + SocketMessengerConstants.DISCONNECT_STRING ) ) stopListening(); } // end if } // end while Determine whether message indicates that user wishes to leave chat room // close BufferedReader (also closes Socket) try { input.close(); } 2003 Prentice Hall, Inc. All rights reserved. 102 103 // handle exception closing BufferedReader 104 catch ( IOException ioException ) { 105 ioException.printStackTrace(); 106 } 107 108 } // end method run 109 110 // stop listening for incoming messages 111 public void stopListening() 112 { 113 keepListening = false; 114 } 115 116 } // end class ReceivingThread Outline ReceivingThread .java 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // Fig. 18.15: MulticastSendingThread.java // MulticastSendingThread is a Thread that broadcasts a chat // message using a multicast datagram. package com.deitel.messenger.sockets.server; import java.io.*; import java.net.*; Outline MulticastSendin gThread.java import com.deitel.messenger.sockets.*; public class MulticastSendingThread extends Thread { // message data private byte[] messageBytes; // MulticastSendingThread constructor public MulticastSendingThread( byte[] bytes ) { // invoke superclass constructor to name Thread super( "MulticastSendingThread" ); messageBytes = bytes; } 2003 Prentice Hall, Inc. All rights reserved. 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 // deliver message to MULTICAST_ADDRESS over DatagramSocket public void run() { // deliver message try { // create DatagramSocket for sending message DatagramSocket socket = new DatagramSocket( SocketMessengerConstants.MULTICAST_SENDING_PORT ); // use InetAddress reserved for multicast group InetAddress group = InetAddress.getByName( SocketMessengerConstants.MULTICAST_ADDRESS ); // create DatagramPacket containing message DatagramPacket packet = new DatagramPacket( messageBytes, messageBytes.length, group, SocketMessengerConstants.MULTICAST_LISTENING_PORT ); // send packet to multicast group and close socket socket.send( packet ); socket.close(); Outline MulticastSendin gThread.java Create DatagramSocket for Lines 32-33 delivering DatagramPackets via multicast Lines 36-37 Linesaddress 40-42 and 45 Specify multicast Create DatagramPacket and send it to clients } 2003 Prentice Hall, Inc. All rights reserved. 49 50 51 52 53 54 55 56 // handle exception delivering message catch ( IOException ioException ) { ioException.printStackTrace(); } } // end method run Outline MulticastSendin gThread.java } // end class MulticastSendingThread 2003 Prentice Hall, Inc. All rights reserved. 18.10.2 DeitelMessenger Client and Supporting Classes • DeitelMessengerServer client – Consists of five components • Interface MessageManager • Class that implements interface MessageManager – Manages communication with server • Thread subclass – Listens for messages at server’s multicast address • Another Thread subclass – Sends messages from client to server • JFrame subclass – Provides client GUI 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // Fig. 18.16: MessageManager.java // MessageManager is an interface for objects capable of managing // communications with a message server. package com.deitel.messenger; public interface MessageManager { // connect to message server and route incoming messages // to given MessageListener public void connect( MessageListener listener ); // disconnect from message server and stop routing // incoming messages to given MessageListener public void disconnect( MessageListener listener ); Outline MessageManager. Connects MessageManager to java DeitelMessengerServer and routes incoming messages to Line 10 appropriate MessageListener Line 14 Disconnects MessageManager from DeitelMessengerServer Line 17 and stops delivering messages to MessageListener // send message to message server public void sendMessage( String from, String message ); } Sends new message to DeitelMessengerServer 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // Fig. 18.17: SocketMessageManager.java // SocketMessageManager communicates with a DeitelMessengerServer using // Sockets and MulticastSockets. package com.deitel.messenger.sockets.client; import java.util.*; import java.net.*; import java.io.*; Outline SocketMessageMa nager.java Line 16 import com.deitel.messenger.*; import com.deitel.messenger.sockets.*; Line 22 public class SocketMessageManager implements MessageManager { // Socket for outgoing messages private Socket clientSocket; Socket for connecting and sending messages to DeitelMessengerServer // DeitelMessengerServer address private String serverAddress; // Thread for receiving multicast messages private PacketReceivingThread receivingThread; Thread listens for incoming messages // flag indicating connection status private boolean connected = false; 2003 Prentice Hall, Inc. All rights reserved. 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 Outline // SocketMessageManager constructor public SocketMessageManager( String address ) { serverAddress = address; } SocketMessageMa nager.java // connect to server and send messages to given MessageListener public void connect( MessageListener listener ) { // if already connected, return immediately if ( connected ) return; // open Socket connection to DeitelMessengerServer try { clientSocket = new Socket( InetAddress.getByName( serverAddress ), SocketMessengerConstants.SERVER_PORT ); Lines 42-44 Line 48 Create Socket to communicate with DeitelMessengerServer // create Thread for receiving incoming messages receivingThread = new PacketReceivingThread( listener ); receivingThread.start(); // update connected flag connected = true; Start Thread that listens for incoming messages 2003 Prentice Hall, Inc. All rights reserved. 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 Outline } // handle exception connecting to server catch ( IOException ioException ) { ioException.printStackTrace(); } } // end method connect SocketMessageMa nager.java Terminates SocketMessageManager connection to DeitelMessengerServer Line 62 // disconnect from server and unregister given MessageListener public void disconnect( MessageListener listener ) { // if not connected, return immediately if ( !connected ) return; // stop listening thread and disconnect from server try { // notify server that client is disconnecting Thread disconnectThread = new SendingThread( clientSocket, "", SocketMessengerConstants.DISCONNECT_STRING ); disconnectThread.start(); 2003 Prentice Hall, Inc. All rights reserved. 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 // wait 10 seconds for disconnect message to be sent disconnectThread.join( 10000 ); // stop receivingThread and remove given MessageListener receivingThread.stopListening(); Outline SocketMessageMa nager.java // close outgoing Socket clientSocket.close(); } // end try // handle exception disconnecting from server catch ( IOException ioException ) { ioException.printStackTrace(); } // handle exception joining disconnectThread catch ( InterruptedException interruptedException ) { interruptedException.printStackTrace(); } // update connected flag connected = false; } // end method disconnect 2003 Prentice Hall, Inc. All rights reserved. 101 102 // send message to server 103 public void sendMessage( String from, String message ) 104 { 105 // if not connected, return immediately 106 if ( !connected ) 107 return; 108 109 // create and start new SendingThread to deliver message 110 new SendingThread( clientSocket, from, message).start(); 111 } 112 113 } // end method SocketMessageManager Outline SocketMessageMa nager.java Line 110 Send message to DeitelMessengerServer 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 // Fig. 18.18: SendingThread.java // SendingThread sends a message to the chat server in a separate Thread. package com.deitel.messenger.sockets.client; import java.io.*; import java.net.*; Outline SendingThread.j ava import com.deitel.messenger.sockets.*; public class SendingThread extends Thread { // Socket over which to send message private Socket clientSocket; private String messageToSend; // SendingThread constructor public SendingThread( Socket socket, String userName, String message ) { // invoke superclass constructor to name Thread super( "SendingThread: " + socket ); clientSocket = socket; // build the message to be sent messageToSend = userName + SocketMessengerConstants.MESSAGE_SEPARATOR + message; 2003 Prentice Hall, Inc. All rights reserved. 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 Outline } // send message and exit Thread public void run() { // send message and flush PrintWriter try { PrintWriter writer = new PrintWriter( clientSocket.getOutputStream() ); writer.println( messageToSend ); writer.flush(); Use } // handle exception sending message catch ( IOException ioException ) { ioException.printStackTrace(); } SendingThread.j ava Lines 34-37 method println of class PrintWriter to send message to DeitelMessengerServer } } // end class SendingThread 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // Fig. 18.19: PacketReceivingThread.java // PacketReceivingThread listens for DatagramPackets containing // messages from a DeitelMessengerServer. package com.deitel.messenger.sockets.client; import java.io.*; import java.net.*; import java.util.*; Outline PacketReceiving Thread.java import com.deitel.messenger.*; import com.deitel.messenger.sockets.*; public class PacketReceivingThread extends Thread { // MessageListener to whom messages should be delivered private MessageListener messageListener; // MulticastSocket for receiving broadcast messages private MulticastSocket multicastSocket; // InetAddress of group for messages private InetAddress multicastGroup; // flag for terminating PacketReceivingThread private boolean keepListening = true; 2003 Prentice Hall, Inc. All rights reserved. 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 Outline // PacketReceivingThread constructor public PacketReceivingThread( MessageListener listener ) { // invoke superclass constructor to name Thread super( "PacketReceivingThread" ); // set MessageListener messageListener = listener; PacketReceiving Thread.java Lines 38-39 MulticastSocket listens for incoming chat messages Lines on port41-42 and port MULTICAST_LISTENING_PORT Line 45 // connect MulticastSocket to multicast address try { multicastSocket = new MulticastSocket( SocketMessengerConstants.MULTICAST_LISTENING_PORT ); multicastGroup = InetAddress.getByName( SocketMessengerConstants.MULTICAST_ADDRESS ); // join multicast group to receive messages multicastSocket.joinGroup( multicastGroup ); InetAddress object to which DeitelMessengerServer multicasts chat messages // set 5 second timeout when waiting for new packetsRegister MulticastSocket multicastSocket.setSoTimeout( 5000 ); to receive messages sent to } MULTICAST_ADDRESS 2003 Prentice Hall, Inc. All rights reserved. 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 // handle exception connecting to multicast address catch ( IOException ioException ) { ioException.printStackTrace(); } } // end PacketReceivingThread constructor // listen for messages from multicast group public void run() { // listen for messages until stopped while ( keepListening ) { // create buffer for incoming message byte[] buffer = new byte[ SocketMessengerConstants.MESSAGE_SIZE ]; // create DatagramPacket for incoming message DatagramPacket packet = new DatagramPacket( buffer, SocketMessengerConstants.MESSAGE_SIZE ); // receive new DatagramPacket (blocking call) try { multicastSocket.receive( packet ); } Outline PacketReceiving Thread.java Lines 65-66 Lines 69-70 Line 74 Create byte array for storing DatagramPacket Create DatagramPacket for storing message Read incoming packet from multicast address 2003 Prentice Hall, Inc. All rights reserved. 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 // handle exception when receive times out catch ( InterruptedIOException interruptedIOException ) { // continue to next iteration to keep listening continue; Outline PacketReceiving Thread.java } Lines 97-98 // handle exception reading packet from multicast group catch ( IOException ioException ) { ioException.printStackTrace(); break; } // put message data in a String String message = new String( packet.getData() ); // trim extra white space from end of message message = message.trim(); // tokenize message to retrieve user name and message body StringTokenizer tokenizer = new StringTokenizer( message, SocketMessengerConstants.MESSAGE_SEPARATOR ); Separate message into two tokens delimited by Message_SEPARATOR 2003 Prentice Hall, Inc. All rights reserved. 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 // ignore messages that do not contain a user // name and message body if ( tokenizer.countTokens() == 2 ) // send message to MessageListener messageListener.messageReceived( tokenizer.nextToken(), // user name tokenizer.nextToken() ); // message body } // end while Outline PacketReceiving Thread.java Lines 105-107 After parsing message, deliver message to Line 113 PacketReceivingThread’s MessageListener MulticastSocket // leave multicast group and close try { multicastSocket.leaveGroup( multicastGroup ); multicastSocket.close(); } Stop receiving messages from multicast address // handle exception reading packet from multicast group catch ( IOException ioException ) { ioException.printStackTrace(); } } // end method run 2003 Prentice Hall, Inc. All rights reserved. 124 // stop listening for new messages 125 public void stopListening() 126 { 127 keepListening = false; 128 } 129 130 } // end class PacketReceivingThread Outline PacketReceiving Thread.java 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 // Fig. 18.20: ClientGUI.java // ClientGUI provides a user interface for sending and receiving // messages to and from the DeitelMessengerServer. package com.deitel.messenger; import import import import import import Outline ClientGUI.java java.io.*; java.net.*; java.awt.*; java.awt.event.*; javax.swing.*; javax.swing.border.*; public class ClientGUI extends JFrame { // JMenu for connecting/disconnecting server private JMenu serverMenu; // JTextAreas for displaying and inputting messages private JTextArea messageArea; private JTextArea inputArea; // JButtons and JMenuItems for connecting and disconnecting private JButton connectButton; private JMenuItem connectMenuItem; private JButton disconnectButton; private JMenuItem disconnectMenuItem; 2003 Prentice Hall, Inc. All rights reserved. 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 // JButton for sending messages private JButton sendButton; // JLabel for displaying connection status private JLabel statusBar; // userName to add to outgoing messages private String userName; // MessageManager for communicating with server private MessageManager messageManager; // MessageListener for receiving incoming messages private MessageListener messageListener; // ClientGUI constructor public ClientGUI( MessageManager manager ) { super( "Deitel Messenger" ); Outline ClientGUI.java Line 38 Line 41 MessageManager handles communication with chat server MessageListener receives incoming messages from MessageManager // set the MessageManager messageManager = manager; // create MyMessageListener for receiving messages messageListener = new MyMessageListener(); 2003 Prentice Hall, Inc. All rights reserved. 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 // create Server JMenu serverMenu = new JMenu ( "Server" ); serverMenu.setMnemonic( 'S' ); JMenuBar menuBar = new JMenuBar(); menuBar.add( serverMenu ); setJMenuBar( menuBar ); Outline ClientGUI.java // create ImageIcon for connect buttons Icon connectIcon = new ImageIcon( getClass().getResource( "images/Connect.gif" ) ); // create connectButton and connectMenuItem connectButton = new JButton( "Connect", connectIcon ); connectMenuItem = new JMenuItem( "Connect", connectIcon ); connectMenuItem.setMnemonic( 'C' ); // create ConnectListener for connect buttons ActionListener connectListener = new ConnectListener(); connectButton.addActionListener( connectListener ); connectMenuItem.addActionListener( connectListener ); // create ImageIcon for disconnect buttons Icon disconnectIcon = new ImageIcon( getClass().getResource( "images/Disconnect.gif" ) ); 2003 Prentice Hall, Inc. All rights reserved. 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 // create disconnectButton and disconnectMenuItem disconnectButton = new JButton( "Disconnect", disconnectIcon ); disconnectMenuItem = new JMenuItem( "Disconnect", disconnectIcon ); disconnectMenuItem.setMnemonic( 'D' ); Outline ClientGUI.java // disable disconnect buttons disconnectButton.setEnabled( false ); disconnectMenuItem.setEnabled( false ); // create DisconnectListener for disconnect buttons ActionListener disconnectListener = new DisconnectListener(); disconnectButton.addActionListener( disconnectListener ); disconnectMenuItem.addActionListener( disconnectListener ); // add connect and disconnect JMenuItems to fileMenu serverMenu.add( connectMenuItem ); serverMenu.add( disconnectMenuItem ); // add connect and disconnect JButtons to buttonPanel JPanel buttonPanel = new JPanel(); buttonPanel.add( connectButton ); buttonPanel.add( disconnectButton ); // create JTextArea for displaying messages messageArea = new JTextArea(); 2003 Prentice Hall, Inc. All rights reserved. 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 // disable editing and wrap words at end of line messageArea.setEditable( false ); messageArea.setWrapStyleWord( true ); messageArea.setLineWrap( true ); Outline ClientGUI.java // put messageArea in JScrollPane to enable scrolling JPanel messagePanel = new JPanel(); messagePanel.setLayout( new BorderLayout( 10, 10 ) ); messagePanel.add( new JScrollPane( messageArea ), BorderLayout.CENTER ); // create JTextArea for entering new messages inputArea = new JTextArea( 4, 20 ); inputArea.setWrapStyleWord( true ); inputArea.setLineWrap( true ); inputArea.setEditable( false ); // create Icon for sendButton Icon sendIcon = new ImageIcon( getClass().getResource( "images/Send.gif" ) ); // create sendButton and disable it sendButton = new JButton( "Send", sendIcon ); sendButton.setEnabled( false ); 2003 Prentice Hall, Inc. All rights reserved. 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 Outline sendButton.addActionListener( new ActionListener() { // send new message when user activates sendButton public void actionPerformed( ActionEvent event ) { messageManager.sendMessage( userName, inputArea.getText()); // clear inputArea inputArea.setText( "" ); } ClientGUI.java Lines 136-137 Send user’s name and inputArea’s text to DeitelMessengerServer as a chat message } ); // lay out inputArea and sendButton in BoxLayout and // add Box to messagePanel Box box = new Box( BoxLayout.X_AXIS ); box.add( new JScrollPane( inputArea ) ); box.add( sendButton ); messagePanel.add( box, BorderLayout.SOUTH ); // create JLabel for statusBar with a recessed border statusBar = new JLabel( "Not Connected" ); statusBar.setBorder( new BevelBorder( BevelBorder.LOWERED ) ); 2003 Prentice Hall, Inc. All rights reserved. 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 // lay out components in JFrame Container container = getContentPane(); container.add( buttonPanel, BorderLayout.NORTH ); container.add( messagePanel, BorderLayout.CENTER ); container.add( statusBar, BorderLayout.SOUTH ); Outline ClientGUI.java Line 170 // add WindowListener to disconnect when user quits addWindowListener ( new WindowAdapter () { // disconnect from server and exit application public void windowClosing ( WindowEvent event ) { messageManager.disconnect( messageListener ); System.exit( 0 ); } } ); Disconnect from chat server when user exits client application } // end ClientGUI constructor // ConnectListener listens for user requests to connect to server private class ConnectListener implements ActionListener { 2003 Prentice Hall, Inc. All rights reserved. 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 // connect to server and enable/disable GUI components public void actionPerformed( ActionEvent event ) { // connect to server and route messages to messageListener When messageManager.connect( messageListener ); Outline ClientGUI.java user accesses Connect menu, connect to chat Lineserver 185 // prompt for userName userName = JOptionPane.showInputDialog( ClientGUI.this, "Enter user name:" ); // clear messageArea messageArea.setText( "" ); // update GUI components connectButton.setEnabled( false ); connectMenuItem.setEnabled( false ); disconnectButton.setEnabled( true ); disconnectMenuItem.setEnabled( true ); sendButton.setEnabled( true ); inputArea.setEditable( true ); inputArea.requestFocus(); statusBar.setText( "Connected: " + userName ); } 2003 Prentice Hall, Inc. All rights reserved. 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 } // end ConnectListener inner class // DisconnectListener listens for user requests to disconnect // from DeitelMessengerServer private class DisconnectListener implements ActionListener { Outline ClientGUI.java // disconnect from server and enable/disable GUI components public void actionPerformed( ActionEvent event ) { // disconnect from server and stop routing messages // to messageListener messageManager.disconnect( messageListener ); // update GUI components sendButton.setEnabled( false ); disconnectButton.setEnabled( false ); disconnectMenuItem.setEnabled( false ); inputArea.setEditable( false ); connectButton.setEnabled( true ); connectMenuItem.setEnabled( true ); statusBar.setText( "Not Connected" ); } } // end DisconnectListener inner class 2003 Prentice Hall, Inc. All rights reserved. 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 // MyMessageListener listens for new messages from MessageManager and // displays messages in messageArea using MessageDisplayer. private class MyMessageListener implements MessageListener { // when received, display new messages in messageArea public void messageReceived( String from, String message ) { // append message using MessageDisplayer and // invokeLater, ensuring thread-safe access messageArea SwingUtilities.invokeLater( new MessageDisplayer( from, message ) ); } Outline ClientGUI.java Lines 239-240 Display message when MessageListener detects that message was received } // MessageDisplayer displays a new message by appending the message to // the messageArea JTextArea. This Runnable object should be executed // only on the Event thread, because it modifies a live Swing component private class MessageDisplayer implements Runnable { private String fromUser; private String messageBody; // MessageDisplayer constructor public MessageDisplayer( String from, String body ) 2003 Prentice Hall, Inc. All rights reserved. 253 { 254 fromUser = from; 255 messageBody = body; 256 } 257 258 // display new message in messageArea 259 public void run() 260 { 261 // append new message 262 messageArea.append( "\n" + fromUser + "> " + messageBody ); 263 264 // move caret to end of messageArea to ensure new 265 // message is visible on screen 266 messageArea.setCaretPosition( messageArea.getText().length() ); 267 } 268 269 } // end MessageDisplayer inner class 270 271 } // end class ClientGUI Outline ClientGUI.java 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 // Fig. 18.21 DeitelMessenger.java // DeitelMessenger is a chat application that uses a ClientGUI // and SocketMessageManager to communicate with DeitelMessengerServer. package com.deitel.messenger.sockets.client; import com.deitel.messenger.*; public class DeitelMessenger { Outline DeitelMessenger .java DeitelMessenger creates Lines 8 and 16-18 SocketMessageManager public static void main( String args[] ) { MessageManager messageManager; Line 16 Line 18 // create new DeitelMessenger if ( args.length == 0 ) messageManager = new SocketMessageManager( "localhost" ); else messageManager = new SocketMessageManager( args[ 0 ] ); // create GUI for SocketMessageManager ClientGUI clientGUI = new ClientGUI( messageManager ); clientGUI.setSize( 300, 400 ); clientGUI.setResizable( false ); clientGUI.setVisible( true ); Create a client to connect to the localhost Connect to a host supplied by the user } } // end class DeitelMessenger 2003 Prentice Hall, Inc. All rights reserved. Outline DeitelMessenger .java 2003 Prentice Hall, Inc. All rights reserved. Outline DeitelMessenger .java 2003 Prentice Hall, Inc. All rights reserved. 18.11 NIO Networking Overview • Non-blocking I/O • Readiness selection – Selectors • SelectableChannel • Selector 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // Fig. 18.22: 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 import import import import import import import import java.io.*; java.nio.*; java.nio.channels.*; java.nio.channels.spi.*; java.nio.charset.*; java.net.*; java.util.*; java.awt.event.*; javax.swing.*; Outline DeitelMessenger NonBlockingServ er.java 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 ); 2003 Prentice Hall, Inc. All rights reserved. 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 public DeitelMessengerNonBlockingServer() { super( "DeitelMessenger Server" ); displayArea = new JTextArea(); getContentPane().add( new JScrollPane( displayArea ) ); setSize( 200, 300 ); setVisible( true ); Outline DeitelMessenger NonBlockingServ er.java Lines 45-46 // 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(); } Close the server and the selector 2003 Prentice Hall, Inc. All rights reserved. 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 finally { System.exit( 0 ); } } } // end inner class WindowAdapter Outline DeitelMessenger NonBlockingServ er.java ); // end addWindowListener Line 69 } // 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 ); Line 75 Create a Charset for UTF-8 encoding Set up the server to be non-blocking 2003 Prentice Hall, Inc. All rights reserved. 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 // 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 ); Outline DeitelMessenger NonBlockingServ er.java Line 93 Lines 94-95 Create the selector Register the server with the selector // process incoming requests while ( selector.select() > 0 ) { 2003 Prentice Hall, Inc. All rights reserved. 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 // 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(); Outline DeitelMessenger NonBlockingServ er.java Line 114 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++; Accept a new connection SwingUtilities.invokeLater( new Runnable() { 2003 Prentice Hall, Inc. All rights reserved. 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 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 Outline DeitelMessenger NonBlockingServ er.java Lines 134-135 Linesthe 144-147 Register new client with the selector } // end if key.isAcceptable else if ( key.isReadable() ) { // ready for read // get socketChannel ready for read SocketChannel socketChannel = ( SocketChannel ) key.channel(); Get a readable channel and read the message from it readMessage( socketChannel ); } } // end processing each channel 2003 Prentice Hall, Inc. All rights reserved. 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 } // end processing incoming requests } // end method getConnection // send message to client private void writeMessage( String message ) throws IOException { Socket socket; SocketChannel socketChannel; Outline DeitelMessenger NonBlockingServ er.java Lines 171 and 174 // 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 ); Encode the message and send it to the client } 2003 Prentice Hall, Inc. All rights reserved. 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 // process problems sending object catch ( IOException ioException ) { ioException.printStackTrace(); socketChannel.close(); sockets.remove( socket ); } Outline DeitelMessenger Close the client NonBlockingServ channel and remove it er.java from the selector } // 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(); Lines 180-181 Line 197 Line 198 Read the message from the client Flip the buffer 2003 Prentice Hall, Inc. All rights reserved. 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 Outline // remove and close the connection when client disconnects if ( message.indexOf( "Disconnect" ) >= 0 ) { sockets.remove( socketChannel.socket() ); DeitelMessenger Close the client socketChannel.close(); NonBlockingServ channel and remove it } er.java from the selector else writeMessage( message ); Line 205 } // end if } // end try catch ( IOException ioException ) { ioException.printStackTrace(); sockets.remove( socketChannel.socket() ); socketChannel.close(); } Lines 216-217 Close the client channel and remove it from the selector } // end method readMessage 2003 Prentice Hall, Inc. All rights reserved. 222 223 224 225 226 227 228 229 } public static void main( String args[] ) { DeitelMessengerNonBlockingServer application = new DeitelMessengerNonBlockingServer(); application.runServer(); } Outline DeitelMessenger NonBlockingServ er.java // end class DeitelMessengerNonBlockingServer 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // Fig. 18.23: SocketMessageManager2.java // SocketMessageManager2 is a class for objects capable of managing // communications with a message server. package com.deitel.messenger.sockets.client; import import import import import import java.io.*; java.nio.*; java.nio.channels.*; java.nio.charset.*; java.net.*; java.util.*; Outline SocketMessageMa nager2.java import com.deitel.messenger.*; public class SocketMessageManager2 implements MessageManager { private SocketChannel socketChannel; private MessageListener messageListener; private String serverAddress; private ReceivingThread receiveMessage; private boolean connected; private Charset charSet = Charset.forName( "UTF-8" ); private ByteBuffer writeBuffer; private ByteBuffer readBuffer = ByteBuffer.allocate( 512 ); 2003 Prentice Hall, Inc. All rights reserved. 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 Outline public SocketMessageManager2( String host ) { serverAddress = host; connected = false; } SocketMessageMa nager2.java // connect to message server and start receiving message public void connect( MessageListener listener ) { messageListener = listener; Line 40 Line 46 // connect to server and start thread to receive message try { Create Socket to communicate with DeitelMessengerServer // create SocketChannel to make connection to server socketChannel = SocketChannel.open(); socketChannel.connect( new InetSocketAddress( InetAddress.getByName( serverAddress ), 12345 ) ); // start ReceivingThread to receive messages sent by server receiveMessage = new ReceivingThread(); receiveMessage.start(); connected = true; } Start Thread that listens for incoming messages 2003 Prentice Hall, Inc. All rights reserved. 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 catch ( Exception exception ) { exception.printStackTrace(); } } // disconnect from message server and stop receiving message public void disconnect( MessageListener listener ) { if ( connected ) { Outline SocketMessageMa nager2.java Line 67 // send disconnect request and stop receiving try { sendMessage( "", "Disconnect" ); connected = false; // send interrupt signal to receiving thread receiveMessage.interrupt(); Interrupt the receiving thread } catch ( Exception exception ) { exception.printStackTrace(); } } } 2003 Prentice Hall, Inc. All rights reserved. 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 // send message to message server public void sendMessage( String userName, String messageBody ) { String message = userName + "> " + messageBody; // send message to server try { writeBuffer = charSet.encode( message ); socketChannel.write( writeBuffer ); } catch ( IOException ioException ) { ioException.printStackTrace(); Outline SocketMessageMa nager2.java Line 83 Encode the message and send it to the client try { socketChannel.close(); } catch ( IOException exception ) { exception.printStackTrace(); } } } // end method sendMessage public class ReceivingThread extends Thread { 2003 Prentice Hall, Inc. All rights reserved. 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 Outline public void run() { int messageLength = 0; String message = ""; SocketMessageMa nager2.java // read messages until server close the connection try { // process messages sent from server do { readBuffer.clear(); socketChannel.read( readBuffer ); readBuffer.flip(); CharBuffer charMessage = charSet.decode( readBuffer ); message = charMessage.toString().trim(); Line 111 Read the message from the 112 client Line Flip the buffer // tokenize message to retrieve user name and message body StringTokenizer tokenizer = new StringTokenizer( message, ">" ); // ignore messages that do not contain a user // name and message body if ( tokenizer.countTokens() == 2 ) 2003 Prentice Hall, Inc. All rights reserved. 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 // send message to MessageListener messageListener.messageReceived( tokenizer.nextToken(), // user name tokenizer.nextToken() ); // message body } while ( true ); // keep receiving messages Outline SocketMessageMa nager2.java } // end try // catch problems reading from server catch ( IOException ioException ) { if ( ioException instanceof ClosedByInterruptException ) System.out.println( "socket channel closed" ); else { ioException.printStackTrace(); try { socketChannel.close(); System.out.println( "socket channel closed" ); } catch ( IOException exception ) { exception.printStackTrace(); } } 2003 Prentice Hall, Inc. All rights reserved. 149 } // end catch 150 151 } // end method run 152 153 } // end inner class ReceivingThread 154 155 } // end class SocketMessageManager2 Outline SocketMessageMa nager2.java 2003 Prentice Hall, Inc. All rights reserved. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 // Fig. 18.24: DeitelMessenger2.java // DeitelMessenger2 is a chat application that uses a ClientGUI // to communicate with chat server. package com.deitel.messenger.sockets.client; import com.deitel.messenger.*; Outline DeitelMessenger 2.java public class DeitelMessenger2 { public static void main( String args[] ) { MessageManager messageManager; // create new DeitelMessenger if ( args.length == 0 ) messageManager = new SocketMessageManager2( "localhost" ); else messageManager = new SocketMessageManager2( args[ 0 ] ); // create GUI for SocketMessageManager ClientGUI clientGUI = new ClientGUI( messageManager ); clientGUI.setSize( 300, 400 ); clientGUI.setResizable( false ); clientGUI.setVisible( true ); } } // end class DeitelMessenger2 2003 Prentice Hall, Inc. All rights reserved. 18.12.1 Creational Design Patterns • Abstract Factory design pattern – Creational design pattern – System determines subclass from which to instantiate objects at runtime – Uses a factory object • Uses an interface to instantiate object – Example: • java.net.SocketFactory creates SocketImpl object 2003 Prentice Hall, Inc. All rights reserved. 18.12.2 Structural Design Patterns • Decorator design pattern – Structural design pattern – Allows object to gain additional responsibilities dynamically – Example: • ObjectOutputStream writes objects to streams (bytes) • FileOutputStream writes bytes to files • We can “decorate” the FileOutputStream with ObjectOutputStream to write objects to files: output = new ObjectOutputStream( new FileOutputStream( fileName ) ); 2003 Prentice Hall, Inc. All rights reserved. 18.12.2 Structural Design Patterns • Facade design pattern – Structural design pattern – Allows one object to represent a subsystem – Example: • Gas pedal is facade object for car’s acceleration subsystem • java.net.URL is a facade object – Can access InetAddress and URLStreamHandler objects through facade 2003 Prentice Hall, Inc. All rights reserved. 18.12.3 Architectural Patterns • Architectural patterns – Promote loose coupling among subsystems – Specify all subsystems and how they interact with each other 2003 Prentice Hall, Inc. All rights reserved. 18.12.3 Architectural Patterns • Model-View-Controller architectural pattern – Model • Contains application data – View • Graphical representation of model – Controller • Input-processing logic 2003 Prentice Hall, Inc. All rights reserved. Fig. 18.25 Model-View-Controller Architecture modifies Controller 2003 Prentice Hall, Inc. All rights reserved. notifies Model View 18.12.3 Architectural Patterns • Layers architectural pattern – Divide system functionality into separate layers • Each layer contains a set of system responsibilities • Designers can modify layer without having to modify others – Example: • Three-tier architecture – Information tier maintains application data (via database) – Middle tier handles business logic – Client tier provides user interface 2003 Prentice Hall, Inc. All rights reserved. Fig. 18.26 Three-tier application model Client tier (Top tier) Middle tier Application Information tier (Bottom tier) Database 2003 Prentice Hall, Inc. All rights reserved.