|
Distributed Computing This website demonstrates using wikis as teaching and learning tool. The course instructor is also happy to share the teaching materials here with those who find it readable. |
Tutorial /
Tutorial - Building an Internet Chat ApplicationActivity 1Let's begin by looking at the product we are going to build before we study how to program this common and well-known Internet application. First of all, use the source code provided to compile into the required byte-codes and execute these byte-codes to see the capability and features of the chat application.
Compile, run, and test the chat client and chat server according to the following steps.
1. Compile the source code ChatClient.java, ChatServer.java, and ChatHandler.java to generate ChatClient.class, ChatServer.class, ChatHandler.class:
2. Then run the chat server program by executing the ChatServer.class:
java ChatServer <port number to listen>
3. After that, test the server by launching the client program several times to connect to the server:
java ChatClient localhost:<port number to listen>
4. Test the client/server chat application by typing text into the input region of a different client's windows to see whether they work as expected.
Illustration of the program
Implementation notes
Activity 2The chat client program we just studied sends only the input message to the server and does not tell the server the identity of the user. This makes the messages displayed in the output region indistinguishable. This situation can be easily remedied by slightly modifying the client program.
Modify the chat client program in a way that when the client intends to send a message to the server, the user name of the client is attached to the message being sent.
Questions1. Why does the class ChatClient need to implement the interfaces ActionListener and WindowListener?
2. State all the methods a class needs to provide when it implements the interface WindowListener?
3. State all the methods a class needs to provide when it implements the interface ActionListener?
4. What is function of the following statement in the constructor?
frame.addWindowListener (this);
5. What is function of the following statement in the constructor?
input.addActionListener (this);
6. What is the advantage of using the readUTF() and writeUTF() methods of data streams to send and receive text?
7. How does a ChatHandler know the total number of the connected ChatClients and where are they when it broadcasts messages to them?
8. Which two stream classes are used in constructing the output stream of ChatHandler?
9. Which two stream classes are used in constructing the input stream of ChatHander?
10. What is the major reason for applying DataOutputStream and DataInputStream when communicating between ChatHandler and ChatClient?
11. Why do we need to synchronize the list of chat handlers in the method broadcast()?
Java CodeChat Server/* * Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import java.io.*; import java.net.*; import java.util.*; public class ChatServer { public static void main (String args[]) throws IOException { if (args.length != 1) throw new IllegalArgumentException ("Syntax: ChatServer <port>"); int port = Integer.parseInt (args[0]); ServerSocket server = new ServerSocket (port); while (true) { Socket client = server.accept (); System.out.println ("Accepted from " + client.getInetAddress ()); ChatHandler handler = new ChatHandler (client); handler.start (); } } } Chat Handler/* * Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import java.io.*; import java.net.*; import java.util.*; public class ChatHandler implements Runnable { protected Socket socket; public ChatHandler (Socket socket) { this.socket = socket; } protected DataInputStream dataIn; protected DataOutputStream dataOut; protected Thread listener; public synchronized void start () { if (listener == null) { try { dataIn = new DataInputStream (new BufferedInputStream (socket.getInputStream ())); dataOut = new DataOutputStream (new BufferedOutputStream (socket.getOutputStream ())); listener = new Thread (this); listener.start (); } catch (IOException ignored) { } } } public synchronized void stop () { if (listener != null) { try { if (listener != Thread.currentThread ()) listener.interrupt (); listener = null; dataOut.close (); } catch (IOException ignored) { } } } protected static Vector handlers = new Vector (); public void run () { try { handlers.addElement (this); while (!Thread.interrupted ()) { String message = dataIn.readUTF (); broadcast (message); } } catch (EOFException ignored) { } catch (IOException ex) { if (listener == Thread.currentThread ()) ex.printStackTrace (); } finally { handlers.removeElement (this); } stop (); } protected void broadcast (String message) { synchronized (handlers) { Enumeration anum = handlers.elements (); while (anum.hasMoreElements ()) { ChatHandler handler = (ChatHandler) anum.nextElement (); try { handler.dataOut.writeUTF (message); handler.dataOut.flush (); } catch (IOException ex) { handler.stop (); } } } } } Chat Client/* * Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import java.io.*; import java.net.*; import java.awt.*; import java.awt.event.*; public class ChatClient implements Runnable, WindowListener, ActionListener { protected String host; protected int port; protected Frame frame; protected TextArea output; protected TextField input; public ChatClient (String host, int port) { this.host = host; this.port = port; frame = new Frame ("ChatClient [" + host + ':' + port + "]"); frame.addWindowListener (this); output = new TextArea (); output.setEditable (false); input = new TextField (); input.addActionListener (this); frame.add ("Center", output); frame.add ("South", input); frame.pack (); } protected DataInputStream dataIn; protected DataOutputStream dataOut; protected Thread listener; public synchronized void start () throws IOException { if (listener == null) { Socket socket = new Socket (host, port); try { dataIn = new DataInputStream (new BufferedInputStream (socket.getInputStream ())); dataOut = new DataOutputStream (new BufferedOutputStream (socket.getOutputStream ())); } catch (IOException ex) { socket.close (); throw ex; } listener = new Thread (this); listener.start (); frame.setVisible (true); } } public synchronized void stop () throws IOException { frame.setVisible (false); if (listener != null) { listener.interrupt (); listener = null; dataOut.close (); } } public void run () { try { while (!Thread.interrupted ()) { String line = dataIn.readUTF (); output.append (line + "\n"); } } catch (IOException ex) { handleIOException (ex); } } protected synchronized void handleIOException (IOException ex) { if (listener != null) { output.append (ex + "\n"); input.setVisible (false); frame.validate (); if (listener != Thread.currentThread ()) listener.interrupt (); listener = null; try { dataOut.close (); } catch (IOException ignored) { } } } public void windowOpened (WindowEvent event) { input.requestFocus (); } public void windowClosing (WindowEvent event) { try { stop (); } catch (IOException ex) { ex.printStackTrace (); } } public void windowClosed (WindowEvent event) {} public void windowIconified (WindowEvent event) {} public void windowDeiconified (WindowEvent event) {} public void windowActivated (WindowEvent event) {} public void windowDeactivated (WindowEvent event) {} public void actionPerformed (ActionEvent event) { try { input.selectAll (); dataOut.writeUTF (event.getActionCommand ()); dataOut.flush (); } catch (IOException ex) { handleIOException (ex); } } public static void main (String[] args) throws IOException { if ((args.length != 1) || (args[0].indexOf (':') < 0)) throw new IllegalArgumentException ("Syntax: ChatClient <host>:<port>"); int idx = args[0].indexOf (':'); String host = args[0].substring (0, idx); int port = Integer.parseInt (args[0].substring (idx + 1)); ChatClient client = new ChatClient (host, port); client.start (); } } Suggested answers are available here. |