diff --git a/assignments/src/MV3500Cohort2024JulySeptember/homework2/Schnitzler/README.md b/assignments/src/MV3500Cohort2024JulySeptember/homework2/Schnitzler/README.md new file mode 100644 index 0000000000000000000000000000000000000000..38a981a6457b9a74e9733f3c93572b085e78108b --- /dev/null +++ b/assignments/src/MV3500Cohort2024JulySeptember/homework2/Schnitzler/README.md @@ -0,0 +1,10 @@ +# Schnitzler Homework 2 + +*** + +## Description +Modification of TcpExample3 and adding some code to implement a chat room with multiple clients. + +The 'SchnitzlerServer' class sets up a server that listens for incoming client connections on port 2317. When a client connects, the server creates a new handler thread for managing communication with that client. Each client's messages are broadcast to all other connected clients. + +The 'SchnitzlerClient' class connects to a server running on localhost at port 2317. It sends user input from the console to the server and displays messages received from the server. \ No newline at end of file diff --git a/assignments/src/MV3500Cohort2024JulySeptember/homework2/Schnitzler/SchnitzlerClient.java b/assignments/src/MV3500Cohort2024JulySeptember/homework2/Schnitzler/SchnitzlerClient.java new file mode 100644 index 0000000000000000000000000000000000000000..82eb4915a5ce1c64fc81d152388f5d8d1dfb1daf --- /dev/null +++ b/assignments/src/MV3500Cohort2024JulySeptember/homework2/Schnitzler/SchnitzlerClient.java @@ -0,0 +1,53 @@ +package MV3500Cohort2024JulySeptember.homework2.Schnitzler; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.Socket; +import java.util.Scanner; + +/** + * + * @author simonschnitzler + */ +public class SchnitzlerClient { + public final static String LOCALHOST = "0:0:0:0:0:0:0:1"; //Local host + + /** + * @param args the command line arguments + * @throws java.lang.Exception + */ + public static void main(String[] args) throws Exception { + Socket socket = new Socket(LOCALHOST, 2317); + + new Thread(new Reader(socket)).start(); + + PrintWriter out = new PrintWriter(socket.getOutputStream(), true); + Scanner scanner = new Scanner(System.in); + while (scanner.hasNextLine()) { + out.println(scanner.nextLine()); + } + } + + private static class Reader implements Runnable { + private BufferedReader in; + + public Reader(Socket socket) throws IOException { + in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + } + + @Override + public void run() { + try { + String message; + while ((message = in.readLine()) != null) { + System.out.println(message); + } + } catch (IOException e) { + System.out.println("Error reading from server: " + e); + } + } + } + +} diff --git a/assignments/src/MV3500Cohort2024JulySeptember/homework2/Schnitzler/SchnitzlerServer.java b/assignments/src/MV3500Cohort2024JulySeptember/homework2/Schnitzler/SchnitzlerServer.java new file mode 100644 index 0000000000000000000000000000000000000000..2f2323f5b3068b963cad413bf7ee3ecf1145723e --- /dev/null +++ b/assignments/src/MV3500Cohort2024JulySeptember/homework2/Schnitzler/SchnitzlerServer.java @@ -0,0 +1,99 @@ +package MV3500Cohort2024JulySeptember.homework2.Schnitzler; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.HashSet; +import java.util.Set; + +/** + * + * @author simonschnitzler + */ +public class SchnitzlerServer { + // the set clientWriters contains form all sockets the active PrintStream + private static Set<PrintWriter> clientWriters = new HashSet<>(); + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + System.out.println(SchnitzlerServer.class.getName() + " has started..."); // it helps debugging to put this on console first + try (ServerSocket listener = new ServerSocket(2317)) { + while (true) { + Handler handler = new Handler(listener.accept()); // create a new thread writing and reading to and from the new socket + OutputStream os = handler.socket.getOutputStream(); + PrintStream ps = new PrintStream(os); + + InetAddress remoteAddress = handler.socket.getInetAddress(); + int remotePort = handler.socket.getPort(); + String message = remoteAddress.getHostName() + "=" + remoteAddress.getHostAddress() + ", " + remotePort + " has connected to the server."; + System.out.println(message); + ps.println("Welcome " + remoteAddress.getHostName() + "=" + remoteAddress.getHostAddress() + ", " + remotePort + " to the group chat!"); + for (PrintWriter writer : clientWriters) { + writer.println(message); + } + ps.flush(); + handler.start(); + } + }catch (IOException e) { + System.err.println("Problem with " + SchnitzlerServer.class.getName() + " networking: " + e); + + // Provide more helpful information to user if exception occurs due to running twice at one time + if (e instanceof java.net.BindException) { + System.err.println("*** Be sure to stop any other running instances of programs using this port!"); + } + } + + } + + private static class Handler extends Thread { + public final Socket socket; + private PrintWriter out; + private BufferedReader in; + + public Handler(Socket socket) { + this.socket = socket; + } + + @Override + public void run() { + try { + in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + out = new PrintWriter(socket.getOutputStream(), true); + + synchronized (clientWriters) { + clientWriters.add(out); + } + + String message; + while ((message = in.readLine()) != null) { + String outputMessage = socket.getInetAddress().getHostName() + "=" + socket.getInetAddress().getHostAddress() + ", " + socket.getPort()+ ": " + message; + System.out.println(outputMessage); + for (PrintWriter writer : clientWriters) { + writer.println(outputMessage); + } + } + } catch (IOException e) { + System.out.println("Error handling client: " + e); + } finally { + try { + socket.close(); + } catch (IOException e) { + System.out.println("Couldn't close a socket, what's going on?"); + } + + synchronized (clientWriters) { + clientWriters.remove(out); + } + } + } + } + +} diff --git a/assignments/src/MV3500Cohort2024JulySeptember/homework2/Schnitzler/package-info.java b/assignments/src/MV3500Cohort2024JulySeptember/homework2/Schnitzler/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..f242324ce45812003d0e3135c3eaa04f81055fde --- /dev/null +++ b/assignments/src/MV3500Cohort2024JulySeptember/homework2/Schnitzler/package-info.java @@ -0,0 +1,10 @@ +/** + * TCP Unicast homework assignments supporting the NPS MOVES MV3500 Networked Graphics course. + * + * @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/tree/master/assignments" target="_blank">networkedGraphicsMV3500 assignments</a> + * @see java.lang.Package + * @see <a href="https://stackoverflow.com/questions/22095487/why-is-package-info-java-useful" target="_blank">StackOverflow: why-is-package-info-java-useful</a> + * @see <a href="https://stackoverflow.com/questions/624422/how-do-i-document-packages-in-java" target="_blank">StackOverflow: how-do-i-document-packages-in-java</a> + */ + +package MV3500Cohort2024JulySeptember.homework2.Schnitzler;