Recipe 16.10 Program: Chat Client


This program is a simple chat program. You can't break in on ICQ or AIM with it, because they each use their own protocol;[5] this one simply writes to and reads from a server, locating the server with the applet method getCodeBase( ). The server for this will be presented in Chapter 17. How does it look when you run it? Figure 16-2 shows me chatting all by myself one day.

[5] For an open source program that "AIMs" to let you talk to both from the same program, check out Jabber at http://www.jabber.org.

Figure 16-2. Chat client in action
figs/jcb2_1602.gif


The code is reasonably self-explanatory. We read from the remote server in a thread to make the input and the output run without blocking each other; this is discussed in Chapter 24. The reading and writing are discussed in this chapter. The program is an applet (see Recipe 18.2) and is shown in Example 16-11.

Example 16-11. ChatRoom.java (chat client)
import java.applet.*; import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.*; /** Simple Chat Room Applet.  * Writing a Chat Room seems to be one of many obligatory rites (or wrongs)  * of passage for Java experts these days.  * <P>  * This one is a toy because it doesn't implement much of a command protocol, which  * means we can't query the server as to * who's logged in,  *  or anything fancy like that. However, it works OK for small groups.  * <P>  * Uses client socket w/ two Threads (main and one constructed),  * one for reading and one for writing.  * <P>  * Server multiplexes messages back to all clients.  */ public class ChatRoom extends Applet {     /** The state */     protected boolean loggedIn;     /* The Frame, for a pop-up, durable Chat Room. */     protected Frame cp;     /** The default port number */     protected static int PORTNUM = 7777;     /** The actual port number */     protected int port;     /** The network socket */     protected Socket sock;     /** BufferedReader for reading from socket */     protected BufferedReader is;     /** PrintWriter for sending lines on socket */     protected PrintWriter pw;     /** TextField for input */     protected TextField tf;     /** TextArea to display conversations */     protected TextArea ta;     /** The Login button */     protected Button lib;     /** The LogOUT button */     protected Button lob;     /** The TitleBar title */     final static String TITLE = "Chat: Ian Darwin's Toy Chat Room Applet";     /** The message that we paint */     protected String paintMessage;     /** Init, overrides method in Applet */     public void init( ) {         paintMessage = "Creating Window for Chat";         repaint( );         cp = new Frame(TITLE);         cp.setLayout(new BorderLayout( ));         String portNum = getParameter("port");         port = PORTNUM;         if (portNum == null)             port = Integer.parseInt(portNum);         // The GUI         ta = new TextArea(14, 80);         ta.setEditable(false);        // readonly         ta.setFont(new Font("Monospaced", Font.PLAIN, 11));         cp.add(BorderLayout.NORTH, ta);         Panel p = new Panel( );         Button b;         // The login button         p.add(lib = new Button("Login"));         lib.setEnabled(true);         lib.requestFocus( );         lib.addActionListener(new ActionListener( ) {             public void actionPerformed(ActionEvent e) {                 login( );                 lib.setEnabled(false);                 lob.setEnabled(true);                 tf.requestFocus( );    // set keyboard focus in right place!             }         });         // The logout button         p.add(lob = new Button("Logout"));         lob.setEnabled(false);         lob.addActionListener(new ActionListener( ) {             public void actionPerformed(ActionEvent e) {                 logout( );                 lib.setEnabled(true);                 lob.setEnabled(false);                 lib.requestFocus( );             }         });         p.add(new Label("Message here:"));         tf = new TextField(40);         tf.addActionListener(new ActionListener( ) {             public void actionPerformed(ActionEvent e) {                 if (loggedIn) {                     pw.println(Chat.CMD_BCAST+tf.getText( ));                     tf.setText("");                  }             }         });         p.add(tf);         cp.add(BorderLayout.SOUTH, p);         cp.addWindowListener(new WindowAdapter( ) {             public void windowClosing(WindowEvent e) {                 // If we do setVisible and dispose, then the Close completes                 ChatRoom.this.cp.setVisible(false);                 ChatRoom.this.cp.dispose( );                 logout( );             }         });         cp.pack( );         // After packing the Frame, centre it on the screen.         Dimension us = cp.getSize( ),              them = Toolkit.getDefaultToolkit( ).getScreenSize( );         int newX = (them.width - us.width) / 2;         int newY = (them.height- us.height)/ 2;         cp.setLocation(newX, newY);         cp.setVisible(true);         paintMessage = "Window should now be visible";         repaint( );     }     /** LOG ME IN TO THE CHAT */     public void login( ) {         if (loggedIn)             return;         try {             sock = new Socket(getCodeBase( ).getHost( ), port);             is = new BufferedReader(new InputStreamReader(sock.getInputStream( )));             pw = new PrintWriter(sock.getOutputStream( ), true);         } catch(IOException e) {             showStatus("Can't get socket: " + e);             cp.add(new Label("Can't get socket: " + e));             return;         }         // construct and start the reader: from server to textarea         // make a Thread to avoid lockups.         new Thread(new Runnable( ) {             public void run( ) {                 String line;                 try {                     while (loggedIn && ((line = is.readLine( )) != null))                         ta.append(line + "\n");                 } catch(IOException e) {                     showStatus("GAA! LOST THE LINK!!");                     return;                 }             }         }).start( );         // FAKE LOGIN FOR NOW         pw.println(Chat.CMD_LOGIN + "AppletUser");         loggedIn = true;     }     /** Log me out, Scotty, there's no intelligent life here! */     public void logout( ) {         if (!loggedIn)             return;         loggedIn = false;         try {             if (sock != null)                 sock.close( );         } catch (IOException ign) {             // so what?         }     }     // It is deliberate that there is no STOP method - we want to keep     // going even if the user moves the browser to another page.     // Anti-social? Maybe, but you can use the CLOSE button to kill      // the Frame, or you can exit the Browser.     /** Paint paints the small window that appears in the HTML,      * telling the user to look elsewhere!      */     public void paint(Graphics g) {         Dimension d = getSize( );         int h = d.height;         int w = d.width;         g.fillRect(0, 0, w, 0);         g.setColor(Color.black);         g.drawString(paintMessage, 10, (h/2)-5);     } }

See Also

This chat applet might not work on all browser flavors; you might need the Java Plug-in. See Recipe 23.6.

There are many better-structured ways to write a chat client, including RMI, Java's RPC interface (see the Introduction to Chapter 22) and the Java Messaging Services, part of the Java 2 Enterprise Edition.

If you need to encrypt your socket connection, check out Sun's JSSE (Java Secure Socket Extension).

For a good overview of network programming from the C programmer's point of view, see the late W. Richard Stevens's Unix Network Programming (Prentice Hall). Despite the book's name, it's really about socket and TCP/IP/UDP programming and covers all parts of the (Unix) networking API and protocols such as TFTP in amazing detail.



Java Cookbook
Java Cookbook, Second Edition
ISBN: 0596007019
EAN: 2147483647
Year: 2003
Pages: 409
Authors: Ian F Darwin

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net