From cca61c9f562d2c9e2be13ec16abe134d209b54e3 Mon Sep 17 00:00:00 2001 From: O'Shea Date: Thu, 10 Dec 2020 14:03:54 -0500 Subject: Final implementation, ready for presentation! --- src/backend/ChatClientCMD.java | 94 ++++++++++++ src/backend/ChatServer.class | Bin 0 -> 1638 bytes src/backend/ChatServer.java | 309 ++++++++++++++++++++++++++++++++++++++++ src/backend/ClientHandler.class | Bin 0 -> 4117 bytes 4 files changed, 403 insertions(+) create mode 100644 src/backend/ChatClientCMD.java create mode 100644 src/backend/ChatServer.class create mode 100644 src/backend/ChatServer.java create mode 100644 src/backend/ClientHandler.class (limited to 'src/backend') diff --git a/src/backend/ChatClientCMD.java b/src/backend/ChatClientCMD.java new file mode 100644 index 0000000..dbaa391 --- /dev/null +++ b/src/backend/ChatClientCMD.java @@ -0,0 +1,94 @@ +package backend; + +import java.net.* ; + +import javax.swing.JFrame ; + +import java.io.* ; + +public class ChatClientCMD + { + + /** + * + * + * @param args + * @throws IOException + */ + public static void main( String[] args ) throws IOException + { + + // Get server IP + BufferedReader keyboard = new BufferedReader( new InputStreamReader( System.in ) ) ; + System.out.print( "\nPlease enter the IP of the desired server: " ); // GUI: IP BOX + + String serverIP = keyboard.readLine() ; + + // Open your connection to a server, at port 6789 + Socket socket = new Socket( serverIP , 6789 ) ; + + // Create communication streams + DataInputStream dataStreamIn = new DataInputStream( socket.getInputStream() ) ; + DataOutputStream dataStreamOut = new DataOutputStream( socket.getOutputStream() ) ; + + // Establish connection, make user-name + System.out.print( "\nConnection established,\nPlease enter a username: " ) ; + String username = keyboard.readLine() ; + dataStreamOut.writeUTF( username ) ; + + ///////////////////////// + //// Program Running //// + ///////////////////////// + + // Thread for sending messages + Thread sendMessage = new Thread(new Runnable() + { + @Override + public void run() + { + System.out.print( "\n-= Type /help for a list of commands =-" ) ; + while( true ) + { + try + { + String messageOut = keyboard.readLine() ; + dataStreamOut.writeUTF( messageOut ) ; + } + catch( IOException x ) + { + x.printStackTrace() ; + System.exit( 0 ) ; + } + } + } + }) ; + + // Thread for receiving messages + Thread receiveMessage = new Thread( new Runnable() + { + + @Override + public void run() + { + while( true ) + { + try + { + String messageIn = dataStreamIn.readUTF() ; + System.out.printf( "%n%s\n", messageIn ) ; + } + catch( IOException x ) + { + x.printStackTrace() ; + System.exit( 0 ) ; + } + } + } + }); + + // Begin threads + sendMessage.start() ; + receiveMessage.start() ; + } + } + // end class ChatClient \ No newline at end of file diff --git a/src/backend/ChatServer.class b/src/backend/ChatServer.class new file mode 100644 index 0000000..f3ea427 Binary files /dev/null and b/src/backend/ChatServer.class differ diff --git a/src/backend/ChatServer.java b/src/backend/ChatServer.java new file mode 100644 index 0000000..c8ebfef --- /dev/null +++ b/src/backend/ChatServer.java @@ -0,0 +1,309 @@ + +package backend ; + +import java.io.DataInputStream ; +import java.io.DataOutputStream ; +import java.io.IOException ; +import java.net.ServerSocket ; +import java.net.Socket ; +import java.util.ArrayList ; + +/** + * ChatServer class accepts Client requests to join + * and creates an individual thread for each client. + * The "brain" of the server. + * + * @author osheas1 + * @author gohringj + * @version Semi-Final Draft + */ +public class ChatServer + { + + // List of all active users in Server + public static ArrayList userList = new ArrayList<>() ; + + + /** + * @param args (unused) + * @throws IOException (is thrown if connection is unexpectedly closed) + */ + public static void main( final String[] args ) throws IOException + { + // Register service on port 6789 + ServerSocket serverSocket = new ServerSocket( 6789 ) ; + Socket socket = null ; + + System.out.println( "\nServer established. Awaiting connections..." ) ; + + // Loop to accept client requests + while ( true ) + { + socket = serverSocket.accept() ; + + DataOutputStream dataStreamOut = new DataOutputStream( socket.getOutputStream() ) ; + DataInputStream dataStreamIn = new DataInputStream( socket.getInputStream() ) ; + + System.out.println( "\nClient connection detected, requesting username..." ) ; + String username = dataStreamIn.readUTF() ; + + ClientHandler handle = new ClientHandler( socket, username, dataStreamOut, dataStreamIn ) ; + + System.out.println( "\nCreating new thread...\n" ) ; + Thread thread = new Thread( handle ) ; + + userList.add( handle ) ; + + thread.start() ; + } + } + } // end class ChatServer + + + + +/** + * ClientHandler class manages the actual messages being sent + * between the users. The "heart" of the server. + * + * @author osheas1 + * @author gohringj + * @version Semi-Final Draft + */ + +class ClientHandler implements Runnable + { + Socket socket ; + String username ; + DataOutputStream dataStreamOut ; + DataInputStream dataStreamIn ; + boolean loggedIn ; + int commandCheck ; + + /** + * Constructor + * @param s = client socket + * @param user = client's user-name + * @param dos = data stream to client + * @param dis = data stream from client + */ + public ClientHandler( Socket s, String user, DataOutputStream dos, DataInputStream dis ) + { + this.socket = s ; + this.username = user ; + this.dataStreamOut = dos ; + this.dataStreamIn = dis ; + this.loggedIn = true ; + } + + + @Override + public void run() + { + // Note the connection of the new user + String announcement = String.format( "\n>>> User \"%s\" has successfully connected (type /help for a list of commands) <<<\n", this.username ) ; + System.out.println( announcement ) ; + + // Distribute announcement to entire server + sendMessage( announcement ) ; + + // Message management + String message = "" ; + while ( true ) + { + // Try-Catch block interprets incoming messages + try + { + message = this.dataStreamIn.readUTF() ; + + if(message == "" || message == " ") + { + continue ; + } + } + catch ( IOException x ) + { + x.printStackTrace() ; + } + + // Check message for user commands, returns TRUE if user "/quit"s + if( commands( message, this ) ) + { + break ; + } + + // Print the message server-side + message = String.format( "%s: %s", this.username, message ) ; + System.out.println( message ) ; + + // Distribute the message to all users + if ( this.commandCheck == 0 ) + { + sendMessage( message ) ; + } + else + { + this.commandCheck = 0 ; + } + } // end while + + // close streams when user disconnects + try + { + this.loggedIn = false ; + this.dataStreamIn.close() ; + this.dataStreamOut.close() ; + this.socket.close() ; + } + catch ( IOException x ) + { + x.printStackTrace() ; + } + } // end run + + + /** + * The 'commands' method manages the usage of user-commands + * by distributing private messages, providing a user-list, + * etc. + * + * @param message = the command itself + * @param user = the user that + * @return = boolean that indicates that the user has disconnected + */ + public boolean commands( String message, final ClientHandler user ) + { + final String[] commands = new String[] { "/help", "/quit", "/userlist", "/pm" } ; + + try + { + // Quit command terminates client's connection, with an announcement + if ( message.equals( "/quit" ) ) + { + this.commandCheck++ ; + String announcement = String.format( "\n-= \"%s\" has disconnected =- \n", user.username ) ; + System.out.println( announcement ) ; + sendMessage( announcement ) ; + return true ; + } + + // User-List command provides the user a list of everyone else connected to the server + if ( message.equals( "/userlist" ) ) + { + this.commandCheck++ ; + user.dataStreamOut.writeUTF( "> Current list of users in the server: " ) ; + for ( ClientHandler users : ChatServer.userList ) + { + if ( !users.loggedIn ) + { + continue ; + } + + user.dataStreamOut.writeUTF( "> " + users.username ) ; + } + } + + // Help command lists all available commands + if ( message.equals( "/help" ) ) + { + this.commandCheck++ ; + user.dataStreamOut.writeUTF( "\n> All available commands: " ) ; + for ( String command : commands ) + { + user.dataStreamOut.writeUTF( "> " +command ) ; + } + + user.dataStreamOut.writeUTF( "\n" ) ; + } + + // Private Message Command allows users to send messages to a single recipient + if ( message.contains( "/pm" ) ) + { + this.commandCheck++ ; + user.dataStreamOut.writeUTF( "\n> Who would you like to private message?" ) ; + String recipient = this.dataStreamIn.readUTF() ; + user.dataStreamOut.writeUTF( "> \"" + recipient + "\"" ) ; + + ClientHandler sendTo = null ; + + // loop determines which ClientHandler object to send the message to + for ( ClientHandler users : ChatServer.userList ) + { + if ( !users.loggedIn ) + { + continue ; + } + else if ( users.username.equals( recipient ) ) + { + sendTo = users ; + } + } + + if ( sendTo == null ) + { + user.dataStreamOut.writeUTF( "\n> User not found, please try again" ) ; + return false ; + } + + user.dataStreamOut.writeUTF( "\n> What would you like to say?" ) ; + String privateMessage = this.dataStreamIn.readUTF() ; + user.dataStreamOut.writeUTF( "> sent: \"" + privateMessage + "\"" ) ; + sendPrivateMessage( privateMessage, user.username, sendTo ) ; + + } + } + + catch ( IOException x ) + { + while ( ChatServer.userList.size() != 0 ) + { + System.out.println( x ) ; + } + } + + return false ; + } // end commands + + + // Convenience method to send messages privately + private static void sendPrivateMessage( String message, final String sentfrom, final ClientHandler sendto ) + { + try + { + for ( ClientHandler users : ChatServer.userList ) + { + if ( users.equals( sendto ) ) + { + message = String.format( "\nFrom <%s>: %s", sentfrom, message ) ; + users.dataStreamOut.writeUTF( message ) ; + } + } + } + catch ( final IOException x ) + { + x.printStackTrace() ; + } + } + + + // Convenience method to distribute messages to all clients + private static void sendMessage( String message ) + { + try + { + for ( ClientHandler users : ChatServer.userList ) + { + if ( !users.loggedIn ) + { + continue ; + } + users.dataStreamOut.writeUTF( message ) ; + } + } + catch ( IOException x ) + { + x.printStackTrace() ; + } + } + } +// end class ClientHandler \ No newline at end of file diff --git a/src/backend/ClientHandler.class b/src/backend/ClientHandler.class new file mode 100644 index 0000000..d0dbaf0 Binary files /dev/null and b/src/backend/ClientHandler.class differ -- cgit v1.3.1-4-g156e