/* 2.0 2023-09-06 Clark Elliott, ColorServer.java and ColorClient.java Copyright (c) 2023 by Dr. Clark Elliott with all rights reserved. D2L submisson: make a copy of your fully running ColorServer.java program named ColorServer.java.txt and submit the .txt file to D2L (required by the plagiarism checker). Name: Dr. Clark Elliott Date: 2023-03-24 Java Version: 20 (build 20+36-2344) Command-line compilation: > javac *.java [executed twice] Code for two standalone running Java processes is contained in this single source code file. Compilation: > javac ColorServer.java > javac ColorServer.java Command-line instructions for running these programs: Client and server can run on the same machine in different processes (in separate terminal windows), or on different machines across the Internet depending on the argument passed to the ColorClient program. To run on localhost: Terminal/CMD window 1> java ColorServer Terminal/CMD window 2> java ColorClient Terminal/CMD window 3> java ColorClient [...] Terminal/CMD window N> java ColorClient Alternatively, to run over the Internet: Terminal/CMD window 1> java ColorServer Terminal/CMD window 2> java ColorClient 172.16.0.98 [But use the actual IP address of the ColorServer] [...] Files needed: ColorServer.java Notes: Using TCP/IP, we send and receive colors from client to server and back again. You can run as many simultaneous ColorClients as you wish and the ColorServer will keep all conversations separate (each request being handled by a different ColorWorker). -------------------- Thanks: https://www.comrevo.com/2019/07/Sending-objects-over-sockets-Java-example-How-to-send-serialized-object-over-network-in-Java.html (Code dated 2019-07-09, by Ramesh) https://rollbar.com/blog/java-socketexception/# Also: Hughes, Shoffner and Winslow for Inet code. -------------------- Of particular interest is that after each request for a new random color, the TCP/IP connection from client to server is broken, which means we are running the system, as mentioned, under a CONNECTIONLESS, STATELESS PROTOCOL. Nonetheless, we keep track of the state of the conversation ourselves, and can see this proven because we always have access to the number of colors that have been traded during the entire conversation. This is significant: if we can keep track of our conversation state with respect to how many color transactions in this toy system, we can also keep track of the state of, say, a banking-transactions conversation when using the web (even though the web uses the stateless HTTP protocol). For those that are new to network programming, my strong recommendation is that you TYPE IN this entire multi-process program yourself. It won't take very long. You'll make mistakes that you'll have to diagnose, and you'll make changes you feel are closer to your style. But you will learn the *langauge* of multi-process, multi-threaded network programming. And, you will always have a running model to refer back to, which limits frustration. If you use my code, be SURE to include the "thanks" links as well. */ import java.io.*; import java.net.*; import java.util.Scanner; class ColorClient { private static int clientColorCount = 0; public static void main(String argv[]) { ColorClient cc = new ColorClient(argv); cc.run(argv); } public ColorClient(String argv[]) { // Constructor System.out.println("\nThis is the constructor if you want to use it.\n"); } public void run(String argv[]) { String serverName; if (argv.length < 1) serverName = "localhost"; // Check for passed server name or IP address. else serverName = argv[0]; String colorFromClient = ""; Scanner consoleIn = new Scanner(System.in); System.out.print("Enter your name: "); System.out.flush (); String userName = consoleIn.nextLine(); System.out.println("Hi " + userName); do { System.out.print("Enter a color, or quit to end: "); colorFromClient = consoleIn.nextLine(); if (colorFromClient.indexOf("quit") < 0){ // Quit has not been entered. getColor(userName, colorFromClient, serverName); } } while (colorFromClient.indexOf("quit") < 0); System.out.println ("Cancelled by user request."); System.out.println (userName + ", You sent and received " + clientColorCount + " colors."); } void getColor(String userName, String colorFromClient, String serverName){ try{ ColorData colorObj = new ColorData(); // Defined in ColorServer, must compile that first. colorObj.userName = userName; colorObj.colorSent = colorFromClient; colorObj.colorCount = clientColorCount; // Socket socket = new Socket("JUNKhost", 45565); // Demonstrate the UH exception below. Socket socket = new Socket(serverName, 45565); System.out.println("\nWe have successfully connected to the ColorServer at port 45,565"); OutputStream OutputStream = socket.getOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(OutputStream); // To serialize the object. oos.writeObject(colorObj); // Marshal the serialized java object to the network. System.out.println("We have sent the serialized values to the ColorServer's server socket"); InputStream InStream = socket.getInputStream(); ObjectInputStream ois = new ObjectInputStream(InStream); ColorData InObject = (ColorData) ois.readObject(); // We now have random access to the color data object. // Important to note! We are maintaining the conversation state while using a connectionless protocol: clientColorCount = InObject.colorCount; // Save in local class variable. System.out.println("\nFROM THE SERVER:"); System.out.println(InObject.messageToClient); System.out.println("The color sent back is: " + InObject.colorSentBack); System.out.println("The color count is: " + InObject.colorCount + "\n"); System.out.println("Closing the connection to the server.\n"); socket.close(); } catch (ConnectException CE){ System.out.println("\nOh no. The ColorServer refused our connection! Is it running?\n"); CE.printStackTrace(); } catch (UnknownHostException UH){ System.out.println("\nUnknown Host problem.\n"); // Test by commenting out / uncommenting out above. UH.printStackTrace(); } catch(ClassNotFoundException CNF){// For the ColorData class defined in the server code. CNF.printStackTrace(); } catch (IOException IOE){ IOE.printStackTrace(); // Describe the problem on the console. } } } class ColorData implements Serializable{ // Must be serializable to send 1 bit after another over the network. String userName; String colorSent; String colorSentBack; String messageToClient; int colorCount; } class ColorWorker extends Thread { // Class definition. Many of these worker threads may run simultaneously. Socket sock; // Class member, socket, local to ColorWorker. ColorWorker (Socket s) {sock = s;} // Constructor, assign arg s to local sock public void run(){ try{ // Get I/O object streams in/out from the socket, then... // ...read in and deserialize the object sent from the client: InputStream InStream = sock.getInputStream(); ObjectInputStream ObjectIS = new ObjectInputStream(InStream); ColorData InObject = (ColorData) ObjectIS.readObject(); // We now have random access to the color data object. OutputStream outStream = sock.getOutputStream(); ObjectOutputStream objectOS = new ObjectOutputStream(outStream); System.out.println("\nFROM THE CLIENT:\n"); System.out.println("Username: " + InObject.userName); System.out.println("Color sent from the client: " + InObject.colorSent); System.out.println("Connections count (State!): " + (InObject.colorCount + 1)); InObject.colorSentBack = getRandomColor(); InObject.colorCount++; InObject.messageToClient = String.format("Thanks %s for sending the color %s", InObject.userName, InObject.colorSent); objectOS.writeObject(InObject); // Send it back. System.out.println("Closing the client socket connection..."); sock.close(); } catch(ClassNotFoundException CNF){ CNF.printStackTrace(); // Class is defined in the server code. } catch (IOException x){ System.out.println("Server error."); x.printStackTrace(); } } String getRandomColor(){ String[] colorArray = new String[] { "Red", "Blue", "Green", "Yellow", "Magenta", "Silver", "Aqua", "Gray", "Peach", "Orange" }; int randomArrayIndex = (int) (Math.random() * colorArray.length); return (colorArray[randomArrayIndex]); } } public class ColorServer { public static void main(String[] args) throws Exception { int q_len = 6; /* Not interesting. Number of simultaneous requests for OpSys to queue */ int serverPort = 45565; Socket sock; System.out.println ("Clark Elliott's Color Server 1.0 starting up, listening at port " + serverPort + ".\n"); // Listen for connections at port serverPort. Doorbell socket: ServerSocket servSock = new ServerSocket(serverPort, q_len); System.out.println("ServerSocket awaiting connections..."); // Will some client ring the doorbell? while (true) { // Use control-C to manually terminate the server. sock = servSock.accept(); // Ding dong! Answer the door! Client connection! // Display our server port + what the system gave us via "Get next available port" for the client connection: System.out.println("Connection from " + sock); new ColorWorker(sock).start();//Spawn a worker thread to handle it. Immediately listen for the next connection. } } } /* ------------------------------------ OUTPUT ------------------------------------ SERVER: > java ColorServer Clark Elliott's Color Server 1.0 starting up, listening at port 45565. ServerSocket awaiting connections... Connection from Socket[addr=/127.0.0.1,port=58155,localport=45565] FROM THE CLIENT: Username: Clark Color sent from the client: Magenta Connections count (State!): 1 Closing the client socket connection... Connection from Socket[addr=/127.0.0.1,port=58156,localport=45565] FROM THE CLIENT: Username: Clark Color sent from the client: Copper Connections count (State!): 2 Closing the client socket connection... -------------------------------------------------------- CLIENT: > java ColorClient This is the constructor if you want to use it. Enter your name: Clark Hi Clark Enter a color, or quit to end: Magenta We have successfully connected to the ColorServer at port 45,565 We have sent the serialized values to the ColorServer's server socket FROM THE SERVER: Thanks Clark for sending the color Magenta The color sent back is: Yellow The color count is: 1 Closing the connection to the server. Enter a color, or quit to end: Copper We have successfully connected to the ColorServer at port 45,565 We have sent the serialized values to the ColorServer's server socket FROM THE SERVER: Thanks Clark for sending the color Copper The color sent back is: Orange The color count is: 2 Closing the connection to the server. Enter a color, or quit to end: quit Cancelled by user request. Clark, You sent and received 2 colors. ---------------------------------------------------------- MY D2L COLORSERVER DISCUSSION FORUM POSTINGS: [insert copies of your two (or more) D2L postings here.] */