Simple console-mode (command-line) chat client

Java programming topics

Simple console-mode (command-line) chat client

Postby Nipuna » Fri Nov 25, 2011 1:02 pm

Syntax: [ Download ] [ Hide ]
Using Java Syntax Highlighting
  1. /*
  2.  * Copyright (c) Ian F. Darwin, <!-- m --><a class="postlink" href="http://www.darwinsys.com/">http://www.darwinsys.com/</a><!-- m -->, 1996-2002.
  3.  * All rights reserved. Software written by Ian F. Darwin and others.
  4.  * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  *
  15.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
  16.  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  17.  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  18.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
  19.  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22.  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23.  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25.  * POSSIBILITY OF SUCH DAMAGE.
  26.  *
  27.  * Java, the Duke mascot, and all variants of Sun's Java "steaming coffee
  28.  * cup" logo are trademarks of Sun Microsystems. Sun's, and James Gosling's,
  29.  * pioneering role in inventing and promulgating (and standardizing) the Java
  30.  * language and environment is gratefully acknowledged.
  31.  *
  32.  * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for
  33.  * inventing predecessor languages C and C++ is also gratefully acknowledged.
  34.  */
  35. import java.applet.*;
  36. import java.awt.*;
  37. import java.awt.event.*;
  38. import java.net.*;
  39. import java.io.*;
  40. import java.net.*;
  41. import java.util.*;
  42.  
  43. /** Simple console-mode (command-line) chat client.
  44.  * @author Ian Darwin, <!-- m --><a class="postlink" href="http://www.darwinsys.com/">http://www.darwinsys.com/</a><!-- m -->
  45.  * @version $Id: ConsChat.java,v 1.6 2004/02/16 02:44:43 ian Exp $
  46.  */
  47. public class ConsChat {
  48.   public static void main(String[] args) throws IOException {
  49.     new ConsChat().chat();
  50.   }
  51.  
  52.   protected Socket sock;
  53.   protected BufferedReader is;
  54.   protected PrintWriter pw;
  55.   protected BufferedReader cons;
  56.  
  57.   protected ConsChat() throws IOException {
  58.     sock = new Socket("localhost", Chat.PORTNUM);
  59.     is   = new BufferedReader(new InputStreamReader(sock.getInputStream()));
  60.     pw   = new PrintWriter(sock.getOutputStream(), true);
  61.     cons = new BufferedReader(new InputStreamReader(System.in));
  62.  
  63.     // Construct and start the reader: from server to stdout.
  64.     // Make a Thread to avoid lockups.
  65.     new Thread() {
  66.       public void run() {
  67.         setName("socket reader thread");
  68.         System.out.println("Starting " + getName());
  69.         System.out.flush();
  70.         String line;
  71.         try {
  72.           // reader thread blocks here
  73.           while ((line = is.readLine()) != null) {
  74.             System.out.println(line);
  75.             System.out.flush();
  76.           }
  77.         } catch (IOException ex) {
  78.           System.err.println("Read error on socket: " + ex);
  79.           return;
  80.         }
  81.       }
  82.     }.start();
  83.   }
  84.  
  85.   protected void chat() throws IOException {
  86.     String text;
  87.  
  88.     System.out.print("Login name: "); System.out.flush();
  89.     text = cons.readLine();
  90.     send(Chat.CMD_LOGIN + text);
  91.  
  92.     // Main thread blocks here
  93.     while ((text = cons.readLine()) != null) {
  94.       if (text.length() == 0 || text.charAt(0) == '#')
  95.         continue;      // ignore null lines and comments
  96.       if (text.charAt(0) == '/')
  97.         send(text.substring(1));
  98.       else send("B"+text);
  99.     }
  100.   }
  101.  
  102.   protected void send(String s) {
  103.     pw.println(s);
  104.     pw.flush();
  105.   }
  106.  
  107. }
  108.  
  109. /** Constants and Class Methods for Java Chat Clients and Server.
  110.  *
  111.  * The protocol:
  112.  *  --> Lusername
  113.  *  --> Btext_to_broadcast
  114.  *  --> Musername\Message
  115.  *  --> Q
  116.  *  <-- any text to be displayed.
  117.  *
  118.  * @author Ian Darwin
  119.  * @version $Id: Chat.java,v 1.3 2004/02/16 02:44:43 ian Exp $
  120.  */
  121. class Chat {
  122.  
  123.   // These are the first character of messages from client to server
  124.  
  125.   public static final int PORTNUM = 9999;
  126.   public static final int MAX_LOGIN_LENGTH = 20;
  127.   public static final char SEPARATOR = '\\';
  128.   public static final char COMMAND = '\\';
  129.   public static final char CMD_LOGIN = 'L';
  130.   public static final char CMD_QUIT  = 'Q';
  131.   public static final char CMD_MESG  = 'M';
  132.   public static final char CMD_BCAST = 'B';
  133.  
  134.   // These are the first character of messages from server to client
  135.  
  136.   public static final char RESP_PUBLIC = 'P';
  137.   public static final char RESP_PRIVATE = 'M';
  138.   public static final char RESP_SYSTEM = 'S';
  139.  
  140.   // TODO in main loop:
  141.   // if (text.charAt(0) == '/')
  142.   //    send(text);
  143.   // else send("B"+text);
  144.  
  145.   public static boolean isValidLoginName(String login) {
  146.     // check length
  147.     if (login.length() > MAX_LOGIN_LENGTH)
  148.       return false;
  149.  
  150.     // check for bad chars
  151.     // if (contains bad chars)
  152.     //  return false
  153.  
  154.     // Passed above tests, is OK
  155.     return true;
  156.   }
  157. }
  158.  
  159. /** Trivial Chat Server to go with our Trivial Chat Client.
  160.  *
  161.  * WARNING -- this code is believed thread-safe but has NOT been 100% vetted
  162.  * by a team of world-class experts for Thread-safeness.
  163.  * DO NOT BUILD ANYTHING CRITICAL BASED ON THIS until you have done so.
  164.  * See the various books on Threaded Java for design issues.
  165.  *
  166.  * @author  Ian F. Darwin, <!-- m --><a class="postlink" href="http://www.darwinsys.com/">http://www.darwinsys.com/</a><!-- m -->
  167.  * @version $Id: ChatServer.java,v 1.10 2004/03/13 21:56:32 ian Exp $
  168.  */
  169. class ChatServer {
  170.   /** What I call myself in system messages */
  171.   protected final static String CHATMASTER_ID = "ChatMaster";
  172.   /** What goes between any handle and the message */
  173.   protected final static String SEP = ": ";
  174.   /** The Server Socket */
  175.   protected ServerSocket servSock;
  176.   /** The list of my current clients */
  177.   protected ArrayList clients;
  178.   /** Debugging state */
  179.   private static boolean DEBUG = false;
  180.  
  181.   /** Main just constructs a ChatServer, which should never return */
  182.   public static void main(String[] argv) {
  183.     System.out.println("DarwinSys Chat Server 0.1 starting...");
  184.     if (argv.length == 1 && argv[0].equals("-debug"))
  185.       DEBUG = true;
  186.     ChatServer w = new ChatServer();
  187.     w.runServer();      // should never return.
  188.     System.out.println("**ERROR* Chat Server 0.1 quitting");
  189.   }
  190.  
  191.   /** Construct (and run!) a Chat Service */
  192.   ChatServer() {
  193.     clients = new ArrayList();
  194.     try {
  195.       servSock = new ServerSocket(Chat.PORTNUM);
  196.       System.out.println("DarwinSys Chat Server Listening on port " +
  197.         Chat.PORTNUM);
  198.     } catch(IOException e) {
  199.       log("IO Exception in ChatServer.<init>" + e);
  200.       System.exit(0);
  201.     }
  202.   }
  203.  
  204.   public void runServer() {
  205.     try {
  206.       while (true) {
  207.         Socket us = servSock.accept();
  208.         String hostName = us.getInetAddress().getHostName();
  209.         System.out.println("Accepted from " + hostName);
  210.         ChatHandler cl = new ChatHandler(us, hostName);
  211.         synchronized (clients) {
  212.           clients.add(cl);
  213.           cl.start();
  214.           if (clients.size() == 1)
  215.             cl.send(CHATMASTER_ID, "Welcome! you're the first one here");
  216.           else {
  217.             cl.send(CHATMASTER_ID, "Welcome! you're the latest of " +
  218.               clients.size() + " users.");
  219.           }
  220.         }
  221.       }
  222.     } catch(IOException e) {
  223.       log("IO Exception in runServer: " + e);
  224.       System.exit(0);
  225.     }
  226.   }
  227.  
  228.   protected void log(String s) {
  229.     System.out.println(s);
  230.   }
  231.  
  232.   /** Inner class to handle one conversation */
  233.   protected class ChatHandler extends Thread {
  234.     /** The client socket */
  235.     protected Socket clientSock;
  236.     /** BufferedReader for reading from socket */
  237.     protected BufferedReader is;
  238.     /** PrintWriter for sending lines on socket */
  239.     protected PrintWriter pw;
  240.     /** The client's host */
  241.     protected String clientIP;
  242.     /** String form of user's handle (name) */
  243.     protected String login;
  244.  
  245.     /* Construct a Chat Handler */
  246.     public ChatHandler(Socket sock, String clnt) throws IOException {
  247.       clientSock = sock;
  248.       clientIP = clnt;
  249.       is = new BufferedReader(
  250.         new InputStreamReader(sock.getInputStream()));
  251.       pw = new PrintWriter(sock.getOutputStream(), true);
  252.     }
  253.  
  254.     /** Each ChatHandler is a Thread, so here's the run() method,
  255.      * which handles this conversation.
  256.      */
  257.     public void run() {
  258.       String line;
  259.       try {
  260.         while ((line = is.readLine()) != null) {
  261.           char c = line.charAt(0);
  262.           line = line.substring(1);
  263.           switch (c) {
  264.           case Chat.CMD_LOGIN:
  265.             if (!Chat.isValidLoginName(line)) {
  266.               send(CHATMASTER_ID, "LOGIN " + line + " invalid");
  267.               log("LOGIN INVALID from " + clientIP);
  268.               continue;
  269.             }
  270.             login = line;
  271.             broadcast(CHATMASTER_ID, login +
  272.               " joins us, for a total of " +
  273.               clients.size() + " users");
  274.             break;
  275.           case Chat.CMD_MESG:
  276.             if (login == null) {
  277.               send(CHATMASTER_ID, "please login first");
  278.               continue;
  279.             }
  280.             int where = line.indexOf(Chat.SEPARATOR);
  281.             String recip = line.substring(0, where);
  282.             String mesg = line.substring(where+1);
  283.             log("MESG: " + login + "-->" + recip + ": "+ mesg);
  284.             ChatHandler cl = lookup(recip);
  285.             if (cl == null)
  286.               psend(CHATMASTER_ID, recip + " not logged in.");
  287.             else
  288.               cl.psend(login, mesg);
  289.             break;
  290.           case Chat.CMD_QUIT:
  291.             broadcast(CHATMASTER_ID,
  292.               "Goodbye to " + login + "@" + clientIP);
  293.             close();
  294.             return;    // The end of this ChatHandler
  295.           
  296.           case Chat.CMD_BCAST:
  297.             if (login != null)
  298.               broadcast(login, line);
  299.             else
  300.               log("B<L FROM " + clientIP);
  301.             break;
  302.           default:
  303.             log("Unknown cmd " + c + " from " + login + "@" + clientIP);
  304.           }
  305.         }
  306.       } catch (IOException e) {
  307.         log("IO Exception: " + e);
  308.       } finally {
  309.         // the sock ended, so we're done, bye now
  310.         System.out.println(login + SEP + "All Done");
  311.         synchronized(clients) {
  312.           clients.remove(this);
  313.           if (clients.size() == 0) {
  314.             System.out.println(CHATMASTER_ID + SEP +
  315.               "I'm so lonely I could cry...");
  316.           } else if (clients.size() == 1) {
  317.             ChatHandler last = (ChatHandler)clients.get(0);
  318.             last.send(CHATMASTER_ID,
  319.               "Hey, you're talking to yourself again");
  320.           } else {
  321.             broadcast(CHATMASTER_ID,
  322.               "There are now " + clients.size() + " users");
  323.           }
  324.         }
  325.       }
  326.     }
  327.  
  328.     protected void close() {
  329.       if (clientSock == null) {
  330.         log("close when not open");
  331.         return;
  332.       }
  333.       try {
  334.         clientSock.close();
  335.         clientSock = null;
  336.       } catch (IOException e) {
  337.         log("Failure during close to " + clientIP);
  338.       }
  339.     }
  340.  
  341.     /** Send one message to this user */
  342.     public void send(String sender, String mesg) {
  343.       pw.println(sender + SEP + mesg);
  344.     }
  345.  
  346.     /** Send a private message */
  347.     protected void psend(String sender, String msg) {
  348.       send("<*" + sender + "*>", msg);
  349.     }
  350.   
  351.     /** Send one message to all users */
  352.     public void broadcast(String sender, String mesg) {
  353.       System.out.println("Broadcasting " + sender + SEP + mesg);
  354.       for (int i=0; i<clients.size(); i++) {
  355.         ChatHandler sib = (ChatHandler)clients.get(i);
  356.         if (DEBUG)
  357.           System.out.println("Sending to " + sib);
  358.         sib.send(sender, mesg);
  359.       }
  360.       if (DEBUG) System.out.println("Done broadcast");
  361.     }
  362.  
  363.     protected ChatHandler lookup(String nick) {
  364.       synchronized(clients) {
  365.         for (int i=0; i<clients.size(); i++) {
  366.           ChatHandler cl = (ChatHandler)clients.get(i);
  367.           if (cl.login.equals(nick))
  368.             return cl;
  369.         }
  370.       }
  371.       return null;
  372.     }
  373.  
  374.     /** Present this ChatHandler as a String */
  375.     public String toString() {
  376.       return "ChatHandler[" + login + "]";
  377.     }
  378.   }
  379. }
  380.  
  381. /**
  382.  * <p>
  383.  * Simple Chat Room Applet.
  384.  * Writing a Chat Room seems to be one of many obligatory rites (or wrongs)
  385.  * of passage for Java experts these days.</p>
  386.  * <p>
  387.  * This one is a toy because it doesn't have much of a protocol, which
  388.  * means we can't query the server as to * who's logged in,
  389.  * or anything fancy like that. However, it works OK for small groups.</p>
  390.  * <p>
  391.  * Uses client socket w/ two Threads (main and one constructed),
  392.  * one for reading and one for writing.</p>
  393.  * <p>
  394.  * Server multiplexes messages back to all clients.</p>
  395.  * @author Ian Darwin
  396.  * @version $Id: ChatRoom.java,v 1.8 2004/03/09 03:59:37 ian Exp $
  397.  */
  398. class ChatRoom extends Applet {
  399.   /** Whether we are being run as an Applet or an Application */
  400.   protected boolean inAnApplet = true;
  401.   /** The state of logged-in-ness */
  402.   protected boolean loggedIn;
  403.   /* The Frame, for a pop-up, durable Chat Room. */
  404.   protected Frame cp;
  405.   /** The default port number */
  406.   protected static int PORTNUM = Chat.PORTNUM;
  407.   /** The actual port number */
  408.   protected int port;
  409.   /** The network socket */
  410.   protected Socket sock;
  411.   /** BufferedReader for reading from socket */
  412.   protected BufferedReader is;
  413.   /** PrintWriter for sending lines on socket */
  414.   protected PrintWriter pw;
  415.   /** TextField for input */
  416.   protected TextField tf;
  417.   /** TextArea to display conversations */
  418.   protected TextArea ta;
  419.   /** The Login button */
  420.   protected Button lib;
  421.   /** The LogOUT button */
  422.   protected Button lob;
  423.   /** The TitleBar title */
  424.   final static String TITLE = "Chat: Ian Darwin's Toy Chat Room Client";
  425.   /** The message that we paint */
  426.   protected String paintMessage;
  427.  
  428.   /** init, overriding the version inherited from Applet */
  429.   public void init() {
  430.     paintMessage = "Creating Window for Chat";
  431.     repaint();
  432.     cp = new Frame(TITLE);
  433.     cp.setLayout(new BorderLayout());
  434.     String portNum = null;
  435.     if (inAnApplet)
  436.       portNum = getParameter("port");
  437.     port = PORTNUM;
  438.     if (portNum != null)
  439.       port = Integer.parseInt(portNum);
  440.  
  441.     // The GUI
  442.     ta = new TextArea(14, 80);
  443.     ta.setEditable(false);    // readonly
  444.     ta.setFont(new Font("Monospaced", Font.PLAIN, 11));
  445.     cp.add(BorderLayout.NORTH, ta);
  446.  
  447.     Panel p = new Panel();
  448.     Button b;
  449.  
  450.     // The login button
  451.     p.add(lib = new Button("Login"));
  452.     lib.setEnabled(true);
  453.     lib.requestFocus();
  454.     lib.addActionListener(new ActionListener() {
  455.       public void actionPerformed(ActionEvent e) {
  456.         login();
  457.         lib.setEnabled(false);
  458.         lob.setEnabled(true);
  459.         tf.requestFocus();  // set keyboard focus in right place!
  460.       }
  461.     });
  462.  
  463.     // The logout button
  464.     p.add(lob = new Button("Logout"));
  465.     lob.setEnabled(false);
  466.     lob.addActionListener(new ActionListener() {
  467.       public void actionPerformed(ActionEvent e) {
  468.         logout();
  469.         lib.setEnabled(true);
  470.         lob.setEnabled(false);
  471.         lib.requestFocus();
  472.       }
  473.     });
  474.  
  475.     p.add(new Label("Message here:"));
  476.     tf = new TextField(40);
  477.     tf.addActionListener(new ActionListener() {
  478.       public void actionPerformed(ActionEvent e) {
  479.         if (loggedIn) {
  480.           pw.println(Chat.CMD_BCAST+tf.getText());
  481.           tf.setText("");
  482.         }
  483.       }
  484.     });
  485.     p.add(tf);
  486.  
  487.     cp.add(BorderLayout.SOUTH, p);
  488.  
  489.         cp.addWindowListener(new WindowAdapter() {
  490.       public void windowClosing(WindowEvent e) {
  491.         // If we do setVisible and dispose, then the Close completes
  492.         ChatRoom.this.cp.setVisible(false);
  493.         ChatRoom.this.cp.dispose();
  494.         logout();
  495.       }
  496.     });
  497.     cp.pack();
  498.     // After packing the Frame, centre it on the screen.
  499.     Dimension us = cp.getSize(),
  500.       them = Toolkit.getDefaultToolkit().getScreenSize();
  501.     int newX = (them.width - us.width) / 2;
  502.     int newY = (them.height- us.height)/ 2;
  503.     cp.setLocation(newX, newY);
  504.     cp.setVisible(true);
  505.     paintMessage = "Window should now be visible";
  506.     repaint();
  507.   }
  508.  
  509.   protected String serverHost = "localhost";
  510.  
  511.   /** LOG ME IN TO THE CHAT */
  512.   public void login() {
  513.     showStatus("In login!");
  514.     if (loggedIn)
  515.       return;
  516.     if (inAnApplet)
  517.       serverHost = getCodeBase().getHost();
  518.     try {
  519.       sock = new Socket(serverHost, port);
  520.       is = new BufferedReader(new InputStreamReader(sock.getInputStream()));
  521.       pw = new PrintWriter(sock.getOutputStream(), true);
  522.     } catch(IOException e) {
  523.       showStatus("Can't get socket to " +
  524.         serverHost + "/" + port + ": " + e);
  525.       cp.add(new Label("Can't get socket: " + e));
  526.       return;
  527.     }
  528.     showStatus("Got socket");
  529.  
  530.     // Construct and start the reader: from server to textarea.
  531.     // Make a Thread to avoid lockups.
  532.     new Thread(new Runnable() {
  533.       public void run() {
  534.         String line;
  535.         try {
  536.           while (loggedIn && ((line = is.readLine()) != null))
  537.             ta.append(line + "\n");
  538.         } catch(IOException e) {
  539.           showStatus("GAA! LOST THE LINK!!");
  540.           return;
  541.         }
  542.       }
  543.     }).start();
  544.  
  545.     // FAKE LOGIN FOR NOW
  546.     pw.println(Chat.CMD_LOGIN + "AppletUser");
  547.     loggedIn = true;
  548.   }
  549.  
  550.   /** Log me out, Scotty, there's no intelligent life here! */
  551.   public void logout() {
  552.     if (!loggedIn)
  553.       return;
  554.     loggedIn = false;
  555.     try {
  556.       if (sock != null)
  557.         sock.close();
  558.     } catch (IOException ign) {
  559.       // so what?
  560.     }
  561.   }
  562.  
  563.   // It is deliberate that there is no STOP method - we want to keep
  564.   // going even if the user moves the browser to another page.
  565.   // Anti-social? Maybe, but you can use the CLOSE button to kill
  566.   // the Frame, or you can exit the Browser.
  567.  
  568.   /** Paint paints the small window that appears in the HTML,
  569.    * telling the user to look elsewhere!
  570.    */
  571.   public void paint(Graphics g) {
  572.     Dimension d = getSize();
  573.     int h = d.height;
  574.     int w = d.width;
  575.     g.fillRect(0, 0, w, 0);
  576.     g.setColor(Color.black);
  577.     g.drawString(paintMessage, 10, (h/2)-5);
  578.   }
  579.  
  580.  
  581.   /** a showStatus that works for Applets or non-Applets alike */
  582.   public void showStatus(String mesg) {
  583.     if (inAnApplet)
  584.       super.showStatus(mesg);
  585.     System.out.println(mesg);
  586.   }
  587.  
  588.   /** A main method to allow the client to be run as an Application */
  589.   public static void main(String[] args) {
  590.     ChatRoom room101 = new ChatRoom();
  591.     room101.inAnApplet = false;
  592.     room101.init();
  593.     room101.start();
  594.   }
  595. }
  596.  
Syntax parsed in 0.183 seconds
User avatar
Nipuna
Promo Team
Promo Team
 
Posts: 2216
Joined: Mon Jan 04, 2010 2:32 pm
Cash on hand: 86,080.30
Bank: 252,701.40
Location: Deraniyagala,SRI LANKA
Medals: 2
EC_Bronze_Star (1) EC_Achievment (1)

Invitations sent: 5
Registered friends: 0
Highscores: 1
Reputation point: 33
Staff Sergeant

Return to Java Programming

Who is online

Users browsing this forum: No registered users and 1 guest