JMeetUp
An Example Using TCP and UDP |
Prof. David Bernstein |
Computer Science Department |
bernstdh@jmu.edu |
package jmeetup; import java.util.*; /** * A Proposal in JMeetUp * * @version 1.0 * @author Prof. David Bernstein, James Madison University */ public class Proposal { private Hashtable<String,String> proponents; // Thread safe private int id; private String description; /** * Default Constructor */ public Proposal() { this(-1, "Default Proposal"); } /** * Explicit Value Constructor */ public Proposal(int id, String description) { this.id = id; this.description = description; proponents = new Hashtable<String,String>(); } /** * Add a new proponent * * @param proponent The new proponent */ public void addProponent(String proponent) { proponents.put(proponent, proponent); } /** * Get the ID of this Proposal * * @return The ID */ public int getID() { return id; } /** * Get all of the proponents for this Proposal * * @return The proponents */ public Enumeration<String> getProponents() { return proponents.elements(); } /** * Remove a proponent * * @param proponent The proponent to remove */ public void removeProponent(String proponent) { proponents.remove(proponent); } /** * Return a String representation of this Proposal * * @return The String */ public String toString() { Enumeration<String> e; String s; s = "("+id+") "+description+"\t\t"; s += "Proponents: "; e = proponents.elements(); while (e.hasMoreElements()) { s += e.nextElement() + " "; } return s; } }
package jmeetup; import java.awt.*; import java.io.*; import java.net.*; import gui.*; import internet.*; /** * A JMeetUp Client * * @version 1.0 * @author Prof. David Bernstein, James Madison University */ public class Client { private BufferedReader in; private UDPMessageReceiver messageReceiver; private PrintWriter out; private Socket s; private String username; /** * Constructor */ public Client(String username, String host, int tcpPort, int udpPort) throws IOException, SocketException { MessageWindow messageWindow; this.username = username; s = new Socket(host, tcpPort); out = new PrintWriter(s.getOutputStream()); in = new BufferedReader( new InputStreamReader(s.getInputStream())); // Send the login information send("login:"+username); send("port:"+udpPort); // Create the GUI components messageWindow = new MessageWindow(); // Start the pieces messageReceiver = new UDPMessageReceiver(udpPort); messageReceiver.addMessageListener(messageWindow); messageReceiver.start(); processCommands(); // Stop the pieces System.out.print("Bye, "); messageReceiver.stop(); messageWindow.setVisible(false); messageWindow.dispose(); System.out.print("bye..."); } /** * Read commands from the console, send them to the server, and * print the responses */ private void processCommands() { BufferedReader cin; String line; cin = new BufferedReader( new InputStreamReader(System.in)); try { while ((line=cin.readLine()) != null) { send(line); line = receive(); System.out.println(line.replaceAll("<BR/>","\n")+"\n"); } send("logout:"+username); } catch (IOException ioe) { ioe.printStackTrace(); } } /** * Receive a line of text * * @return The text */ private String receive() { String line; line = null; try { line = in.readLine(); } catch (IOException ioe) { // Ignore it } return line; } /** * Send a line of text * * @param text The text to send */ private void send(String text) { out.println(text); out.flush(); } }
package jmeetup; import java.awt.*; import java.io.*; import java.net.*; import java.util.*; import javax.swing.*; import gui.*; import internet.*; /** * The JMeetUp server * * @version 1.0 * @author Prof. David Bernstein, James Madison University */ public class Server implements Runnable { private volatile boolean keepRunning; private Hashtable<ConnectionHandler, ConnectionHandler> tcpHandlers; // Thread safe private Hashtable<ConnectionHandler, UDPMessageSender> udpHandlers; // Thread safe private ServerSocket ss; private Thread controlThread; private Vector<Proposal> proposals; // Thread safe /** * Default Constructor */ public Server() { this(9000); } /** * Explicit Value Constructor * * @param port The port the server should listen to */ public Server(int port) { try { ss = new ServerSocket(port); // Make sure accept() will timeout so that we can stop ss.setSoTimeout(5000); tcpHandlers = new Hashtable<ConnectionHandler,ConnectionHandler>(); udpHandlers = new Hashtable<ConnectionHandler,UDPMessageSender>(); proposals = new Vector<Proposal>(); } catch (Exception e) { System.err.println(e); System.exit(1); } } /** * Add a proponent to a Proposal * * @param id The ID of the proposal * @param username The proponent */ public synchronized void addProponent(int id, String username) { Enumeration<Proposal> e; Proposal p; e = proposals.elements(); while (e.hasMoreElements()) { p = e.nextElement(); if (p.getID() != id) p.removeProponent(username); else p.addProponent(username); } } /** * Add a Proposal * * @param username The user making the proposal * @param description Decscription of the proposal */ public synchronized void addProposal(String username, String description) { int id; Proposal p; id = proposals.size() + 1; p = new Proposal(id, description); proposals.add(p); addProponent(id, username); } /** * Broadcast a message * * @param message The message */ public synchronized void broadcast(String message) { Enumeration<ConnectionHandler> e; ConnectionHandler tcph; UDPMessageSender udph; e = tcpHandlers.elements(); while (e.hasMoreElements()) { tcph = e.nextElement(); udph = udpHandlers.get(tcph); if (udph != null) udph.send(message); } } /** * Get all of the proposals * * @return The proposals */ public synchronized Enumeration<Proposal> getProposals() { return proposals.elements(); } /** * Remove a connection handler * * @param name The name */ public void remove(ConnectionHandler handler) { ConnectionHandler tcph; UDPMessageSender udph; tcph = tcpHandlers.remove(handler); udph = udpHandlers.remove(handler); if (udph != null) udph.stop(); if (tcph != null) tcph.stop(); } /** * Remove all connection handlers * */ public void removeAll() { Enumeration<ConnectionHandler> e; ConnectionHandler handler; e = tcpHandlers.elements(); while (e.hasMoreElements()) { handler = e.nextElement(); remove(handler); } } /** * The "entry point" for the new thread of execution */ public void run() { ConnectionHandler tcph; UDPMessageSender udph; Socket s; while (keepRunning) { try { s = ss.accept(); udph = new UDPMessageSender(s.getInetAddress()); udph.start(); try { tcph =new ConnectionHandler(s,this); // Use the ConnectionHandler // as the key in both cases since // it will initiate the remove later tcpHandlers.put(tcph, tcph); udpHandlers.put(tcph, udph); tcph.start(); } catch (IOException ioet) { ioet.printStackTrace(); } } catch (SocketException se) { // Unable to create UDP socket or accept() timed-out } catch (IOException ioes) { // Unable to accept } } // The thread is about to terminate so remove all of the // handlers removeAll(); controlThread = null; } /** * Set the port for the UDPMessageSender * * @param handler The ConnectionHandler * @param port The port to use */ public void setSenderPort(ConnectionHandler handler, int port) { ConnectionHandler tcph; UDPMessageSender udph; tcph = tcpHandlers.get(handler); udph = udpHandlers.get(handler); if (udph != null) udph.setPort(port); } /** * Start the new thread of execution */ public void start() { if (controlThread == null) { keepRunning = true; controlThread = new Thread(this); controlThread.start(); } } /** * Stop the thread of execution */ public void stop() { keepRunning = false; } }
package jmeetup; import java.io.*; import java.net.*; import java.util.*; /** * Handles an individual connection with a * JMeetUp client * * @version 1.0 * @author Prof. David Bernstein, James Madison University */ public class ConnectionHandler implements Runnable { private volatile boolean keepRunning; private BufferedReader in; private PrintWriter out; private Socket s; private String username; private Thread controlThread; private Server server; /** * Construct a new ConnectionHandler * * @param s The Socket to use * @param server The "controlling" server */ public ConnectionHandler(Socket s, Server server) throws IOException { this.server = server; this.s = s; in = new BufferedReader( new InputStreamReader( s.getInputStream())); out = new PrintWriter(s.getOutputStream()); } /** * Handle a check */ private void handleCheck() { Enumeration<Proposal> e; Proposal p; e = server.getProposals(); while (e.hasMoreElements()) { p = e.nextElement(); out.print(p+"<BR/>"); } out.print("\n"); out.flush(); } /** * Handle a choice */ private void handleChoose(String number) { int id; try { id = Integer.parseInt(number); server.addProponent(id, username); out.println("OK"); out.flush(); } catch (NumberFormatException nfe) { out.println(number+" is an invalid choice!"); out.flush(); } } /** * Handle a login */ private void handleLogin(String name) { // Only change the username if it hasn't // already been set if (username == null) { username = name; System.out.println("["+username+"] on "+ s.getInetAddress()+", "+ s.getPort()); } } /** * Handle a logout */ private void handleLogout() { // Close the socket and stop the thread stop(); } /** * Handle a port change * * @param s The port */ private void handlePort(String s) { int port; try { port = Integer.parseInt(s); server.setSenderPort(this, port); } catch (NumberFormatException nfe) { // Don't change the port } } /** * Handle a proposal * * @param description The texr of the proposal */ private void handlePropose(String description) { server.addProposal(username, description); out.println("OK"); out.flush(); } /** * Handle a talk command * * @param message The message to send */ private void handleTalk(String message) { server.broadcast("["+username+"] "+message); out.println("OK"); out.flush(); } /** * Run this ConnectionHandler */ public void run() { String argument, command, line, name, value; StringTokenizer st; while (keepRunning) { try { line = in.readLine(); command = ""; argument = ""; st = new StringTokenizer(line, ":"); // Parse the command if (st.hasMoreTokens()) command = st.nextToken(); if (st.hasMoreTokens()) { argument = st.nextToken().trim(); } else { if (!command.equals("check")) { argument = command; command = "talk"; } } // Process the command // // Note: This could be improved with the // Command Pattern if (command.equals("check")) { handleCheck(); } else if (command.equals("choose")) { handleChoose(argument); } else if (command.equals("login")) { handleLogin(argument); } else if (command.equals("logout")) { handleLogout(); } else if (command.equals("port")) { handlePort(argument); } else if (command.equals("propose")) { handlePropose(argument); } else if (command.equals("talk")) { handleTalk(argument); } } catch (IOException ioe) { // Ignore it } } // The thread is about to die try { in.close(); out.close(); s.close(); } catch (IOException ioe) { // Ignore } controlThread = null; } /** * Start the new thread of execution */ public void start() { if (controlThread == null) { keepRunning = true; controlThread = new Thread(this); controlThread.start(); } } /** * Stop the thread of execution */ public void stop() { keepRunning = false; } }