/** * This is a simple server class that was created to run a program in a distributed manner. The server is responsible for sending the client enough * information so that the client can work on some problem and respond. * * This setting assumes that the client knows what case K is. It is possible that the server knows the input to all of the cases. If this is true, * then the server is modified to send case information to each client. * * It is assumed that each cases will take a non-trivial amount of time to execute. If a client can solve a case in milliseconds, then it might be * worthwhile modifying this code to send more than 1 case at a time to the client. Consider line number 99. Instead of sending case "K" to the user, one * could modify that to send "K,K+20" or something similar to tell the client to solve multiple cases. * The majority of this code does not need to be modified. However, there are several places that can be customized depending on your needs: * 1. Port number on line 26. Change if you want to listen on a different port. * 2. The number of cases to solve on line 32. * 3. The hashcode on line 88. Change whenever you make changes to the MyClient.java file. Run the HashCode.java file to determine what value needs to be copied to this line. * 3. The information sent to each client on line 93-99. In this template, a "case number" is sent to each client to solve. You may want to send more than just a number. You may wish to send data that the client needs to process. That data could be stored on the server. * 4. The response from the client on line 101. In this template, the response is ignored and a new case is sent to the client. If the response from the client is important and needs to be remembered, this information can be stored near line 101. */ import java.io.*; import java.net.*; import java.util.*; public class MyServer{ //The port that our server listens on. private static final int PORT = 9450; //all cases to be done private static ArrayList cases = new ArrayList<>(); private static HashSet stillToBeCompleted = new HashSet<>(); private static int nextCase = 0; private static int totalNumberOfCases = 500; /** * Main method that waits for clients to connect. Usage: * * java MyServer */ public static void main(String args[]) throws Exception{ System.out.println("The server is running!"); for(int i=1; i<=totalNumberOfCases; i++){ cases.add(i); stillToBeCompleted.add(i); } //A listener socket that listens for any incoming connections. ServerSocket listener = new ServerSocket(PORT); try{ //The program runs in an infinite loop waiting for new clients to attach to the server. while(true){ new ServerListener(listener.accept()).start(); } } finally{ //When the server ends, the listener is shutdown. listener.close(); } } /** * A private class that "listens" for new clients to connect. * A new ServerListener object is created for each client. */ private static class ServerListener extends Thread{ //Administrative stuff to keep the connection working. No need to modify. private Socket socket; private BufferedReader in; private PrintWriter out; public ServerListener(Socket socket){ this.socket = socket; } /** * The method that runs each time a client makes a connection to the server. */ public void run(){ int sendMe = -1; try{ //The "in" variable is data that comes from the client. //The "out" variable is data the server sends to the client. in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new PrintWriter(socket.getOutputStream(), true); //This is done to ensure that the client connecting is the client we want running. //Done for several reasons. Ensures that old clients are not running and connecting to the server. //Also ensures that nothing nefarious is happening if the wrong client is run on purpose. out.println("Verify"); String response = in.readLine(); if(response.equals("86a9a8ac3ba99751e9a85aa2c27453fe7f5f917e")){ //client provided correct hashcode, server can start sending cases to client. out.println("PASSED"); while(nextCase < cases.size()){ //ensure no other clients are accessing this case at the same time synchronized(cases){ sendMe = cases.get(nextCase++); } //Send the case to the client to solve. This assumes the client is solving 1 case at a time. //This line, along with the previous synchronized block, can be modified to get multiple cases //at a time and send them to the client at one time. out.println(Integer.toString(sendMe)); response = in.readLine(); //The client may respond with information about a case that the server can store. //Store response into a file or whatever needs to be done with a response. //Remove case from cases that still need to be completed. synchronized(stillToBeCompleted){ stillToBeCompleted.remove(sendMe); } } out.println("FINISHED"); } else{ out.println("FAILED"); } } catch(Exception e){ //Something really bad happened. Add case back to cases to be solved. //Print error along with informational message that a case was added back to the list. e.printStackTrace(); System.out.println(sendMe +" added back to list."); synchronized(cases){ cases.add(sendMe); } } finally{ //The client is quitting so remove the name from the list and //remove the writer from the list of clients to contact. try{ socket.close(); } catch(IOException e){ //Something really, really bad happened, not much we can do about it. e.printStackTrace(); } } } } }