diff --git a/assignments/src/MV3500Cohort2024JulySeptember/homework2/Matiski/Matiski2Client.java b/assignments/src/MV3500Cohort2024JulySeptember/homework2/Matiski/Matiski2Client.java new file mode 100644 index 0000000000000000000000000000000000000000..26dbd0604ae39d1cd4760b5652b1a3e81ad5dca2 --- /dev/null +++ b/assignments/src/MV3500Cohort2024JulySeptember/homework2/Matiski/Matiski2Client.java @@ -0,0 +1,102 @@ +package MV3500Cohort2024JulySeptember.homework2.Matiski; + +import java.io.*; +import java.net.*; + +/** + * This client program establishes a socket connection to the {@link TcpExamples.TcpExample4DispatchServer}, + * then checks how long it takes to read the single line it expects as a server response. + * The modification I have added is it checks for a password from the server. And it matches it says success and disconnects + * No fancy footwork here, it is pretty simple and similar to {@link TcpExamples.TcpExample3Client}. + * + * @see TcpExample4DispatchServer + * @see TcpExample4HandlerThread + * + * @see <a href="../../../src/TcpExamples/TcpExample4TerminalLog.txt" target="blank">TcpExample4TerminalLog.txt</a> + * @see <a href="../../../src/TcpExamples/TcpExample4SequenceDiagram.png" target="blank">TcpExample4SequenceDiagram.png</a> + * @see <a href="../../../src/TcpExamples/TcpExample4SequenceSketch.png" target="blank">TcpExample4SequenceSketch.png</a> + * credit to the following for providing the class example that I modified + * @author Don McGregor + * @author Don Brutzman + * @author MV3500 class + * @MarkMM + */ +public class Matiski2Client +{ + /** Default constructor */ + public Matiski2Client() + { + // default constructor + } + static String DESTINATION_HOST = "localhost"; + static int MAX_LOOP_COUNT = 4; + + /** + * Program invocation, execution starts here + * @param args command-line arguments + */ + public static void main(String[] args) { + try { + System.out.println(Matiski2Client.class.getName() + " start, loop " + MAX_LOOP_COUNT + " times"); + System.out.println("======================================================="); + for (int loopCount = 1; loopCount <= MAX_LOOP_COUNT; loopCount++) // loop then exit + { + System.out.println(Matiski2Client.class.getName() + " creating new socket #" + loopCount + "..."); + + long startTime = System.currentTimeMillis(); + + // Open a socket for each loop + Socket socket = new Socket(DESTINATION_HOST, 2317); + // Note our local port on this client host is not specified - because + // that doesn't matter. It is an "ephemeral" port on localhost. + + // Setup. Read the prompt from the server. + InputStream is = socket.getInputStream(); + Reader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + + OutputStream os = socket.getOutputStream(); + PrintStream ps = new PrintStream(os); + + // Read server prompt for password + String serverPrompt = br.readLine(); + System.out.println(serverPrompt); // Should print "Enter password:" + + // Send the password + String password = "Mark"; // Replace with your password + ps.println(password); + ps.flush(); + + // Read server response + String serverResponse = br.readLine(); + System.out.println(serverResponse); + + if ("Password accepted. Processing your request...".equals(serverResponse)) { + // Read the actual message from the server + String serverMessage = br.readLine(); + long readTime = System.currentTimeMillis(); + long timeLength = readTime - startTime; + + System.out.println(Matiski2Client.class.getName() + ": message received from server='" + serverMessage + "'"); + System.out.println(Matiski2Client.class.getName() + ": time msec required for read=" + timeLength); + } + + System.out.println("======================================================="); + socket.close(); // Close the socket after the interaction + } + System.out.println(Matiski2Client.class.getName() + " complete"); + // main method now exits + } catch (IOException e) { + System.out.println("Problem with " + Matiski2Client.class.getName() + " networking:"); // describe what is happening + System.out.println("Error: " + e); + // Provide more helpful information to user if exception occurs due to running twice at one time + if (e instanceof java.net.BindException) { + System.out.println("*** Be sure to stop any other running instances of programs using this port!"); + } + else if (e instanceof java.net.ConnectException) + { + System.out.println("*** Be sure to start the server before starting the client!"); + } + } + } +} \ No newline at end of file diff --git a/assignments/src/MV3500Cohort2024JulySeptember/homework2/Matiski/Matiski2HandlerThread.java b/assignments/src/MV3500Cohort2024JulySeptember/homework2/Matiski/Matiski2HandlerThread.java new file mode 100644 index 0000000000000000000000000000000000000000..2de45ad079c4fc7017d7d4bd25cba1c17ecbe998 --- /dev/null +++ b/assignments/src/MV3500Cohort2024JulySeptember/homework2/Matiski/Matiski2HandlerThread.java @@ -0,0 +1,110 @@ +package MV3500Cohort2024JulySeptember.homework2.Matiski; + +import java.io.*; +import java.net.*; + +/** + * <p> + * This utility class supports the {@link TcpExamples.TcpExample4DispatchServer} program, + * handling all programming logic needed for a new socket connection + * to run in a thread of its own. This is the server + * portion as well, so we artificially invent what happens + * if the server can't respond to a connection for several seconds. + * </p> + * <p> + * Warning: do not run this class! It is created and used automatically by {@link TcpExamples.TcpExample4DispatchServer} at run time. + * </p> + * + * @see TcpExample4Client + * @see TcpExample4DispatchServer + * + * @see <a href="../../../src/TcpExamples/TcpExample4TerminalLog.txt" target="blank">TcpExample4TerminalLog.txt</a> + * @see <a href="../../../src/TcpExamples/TcpExample4SequenceDiagram.png" target="blank">TcpExample4SequenceDiagram.png</a> + * @see <a href="../../../src/TcpExamples/TcpExample4SequenceSketch.png" target="blank">TcpExample4SequenceSketch.png</a> + * + * @author Don McGregor + * @author Don Brutzman + * @author MV3500 class + */ +public class Matiski2HandlerThread extends Thread +{ + /** The socket connection to a client */ + Socket socket; + + /** + * The thread constructor creates the socket from a ServerSocket, waiting for the client to connect, + * and passes that socket when constructing the thread responsible for handling the connection. + * + * @param socket The socket connection handled by this thread + */ + Matiski2HandlerThread(Socket socket) + { + this.socket = socket; + } + /** + * Program invocation and execution starts here - but is illegal and unwanted, so warn the unsuspecting user! + * @param args command-line arguments + */ + public static void main(String[] args) + { + System.out.println ("*** TcpExample4HandlerThread is not a standalone executable progam."); + System.out.println ("*** Please run TcpExample4DispatchServer instead... now exiting."); + } + + /** Handles one connection. We add an artificial slowness + * to handling the connection with a sleep(). This means + * the client won't see a server connection response for ten seconds (default). + */ + // @overriding run() method in Java Thread class is deliberate + @Override +public void run() +{ + try + { + System.out.println(Matiski2HandlerThread.class.getName() + " starting to handle a thread..."); + + // Set up input and output streams for communication + InputStream is = socket.getInputStream(); + Reader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + + OutputStream os = socket.getOutputStream(); + PrintStream ps = new PrintStream(os); + + // Ask for password + final String correctPassword = "Mark"; + ps.println("Enter password:"); + ps.flush(); + + String clientPassword = br.readLine(); // Read the password sent by the client + + if (correctPassword.equals(clientPassword)) { + ps.println("Password accepted. Processing your request..."); + ps.flush(); + + final long TIMEOUT = 2000; // 2000 milliseconds = 2 seconds + System.out.println(Matiski2HandlerThread.class.getName() + " pausing for TIMEOUT=" + TIMEOUT + "ms" + + " to emulate computation and avoid server-side overload"); + Thread.sleep(TIMEOUT); + + // Continue with the original logic + ps.println("This message was written by the server " + Matiski2HandlerThread.class.getName()); + ps.flush(); + } else { + ps.println("Incorrect password. Connection will be terminated."); + ps.flush(); + } + + socket.close(); // Close the socket after handling the connection + System.out.println(Matiski2HandlerThread.class.getName() + " finished handling a thread, now exit."); + } + catch(IOException | InterruptedException e) + { + System.out.println("Problem with " + Matiski2HandlerThread.class.getName() + " networking:"); + System.out.println("Error: " + e); + + if (e instanceof java.net.BindException) + System.out.println("*** Be sure to stop any other running instances of programs using this port!"); + } +} +} diff --git a/assignments/src/MV3500Cohort2024JulySeptember/homework2/Matiski/Matiski2Server.java b/assignments/src/MV3500Cohort2024JulySeptember/homework2/Matiski/Matiski2Server.java new file mode 100644 index 0000000000000000000000000000000000000000..7676d44b9b53f3e8f41ddef3fa824006d9b435e2 --- /dev/null +++ b/assignments/src/MV3500Cohort2024JulySeptember/homework2/Matiski/Matiski2Server.java @@ -0,0 +1,65 @@ +package MV3500Cohort2024JulySeptember.homework2.Matiski; + +import java.io.IOException; +import java.net.*; + +/** + * This server program works a bit differently by creating and dispatching a + * new thread to handle multiple incoming socket connections, one after another, all running in parallel. + * This advanced technique is often used in high=performance high=capacity server programs. + * + * + * @see TcpExample4Client + * @see Matiski2HandlerThread + * + * @see <a href="../../../src/TcpExamples/TcpExample4TerminalLog.txt" target="blank">TcpExample4TerminalLog.txt</a> + * @see <a href="../../../src/TcpExamples/TcpExample4SequenceDiagram.png" target="blank">TcpExample4SequenceDiagram.png</a> + * @see <a href="../../../src/TcpExamples/TcpExample4SequenceSketch.png" target="blank">TcpExample4SequenceSketch.png</a> + * + * @author Don McGregor + * @author Don Brutzman + * @author MV3500 class + */ +public class Matiski2Server +{ + /** Default constructor */ + public Matiski2Server() + { + // default constructor + } + /** + * Program invocation, execution starts here + * @param args command-line arguments + */ + public static void main(String[] args) + { + try { + ServerSocket serverSocket = new ServerSocket(2317); + Matiski2HandlerThread handlerThread; + Socket clientConnection; + + int connectionCount = 0; // state variable + + System.out.println(Matiski2Server.class.getName() + " ready to accept socket connections..."); + while (true) // infinite loop + { + clientConnection = serverSocket.accept(); // block until connected + + connectionCount++; // unblocked, got another connection + System.out.println("============================================================="); + System.out.println(Matiski2Server.class.getName() + ".handlerThread invocation for connection #" + connectionCount + "..."); + handlerThread = new Matiski2HandlerThread(clientConnection); + handlerThread.start(); // invokes the run() method in that object + System.out.println(Matiski2Server.class.getName() + ".handlerThread is launched, awaiting another connection..."); + } + } catch (IOException e) { + System.out.println("Problem with " + Matiski2Server.class.getName() + " networking:"); // describe what is happening + System.out.println("Error: " + e); + // Provide more helpful information to user if exception occurs due to running twice at one time + if (e instanceof java.net.BindException) { + System.out.println("*** Be sure to stop any other running instances of programs using this port!"); + } + } + System.out.println("============================================================="); + } +}