package csci3366sample.masterworker.sockets; import java.io.IOException; import java.io.Serializable; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.List; import java.util.LinkedList; /** * Generic example of master/worker program. * "Tasks" just consist of sleeping for a specified time; times to wait are * generatedly randomly from 1 to a specified maximum. * * Command-line arguments: total tasks, maximum task time, port number, * (optional) "--verbose" for verbose output * * Master process for client/server version using sockets and a * less-centralized approach (with the number of workers not known to * the server). * * This version does not try to measure total execution time; it's not * clear that would be meaningful. */ public class Master2 extends Master { /* variables to be used by multiple threads */ private ServerSocket serverSocket; private volatile boolean serverSocketShutDownOnEmptyQueue = false; private List workerThreads = new LinkedList(); /** * Main method. */ public static void main(String[] args) { String usageMessage = "parameters: numTasks maxTaskTime portNum [--verbose]"; final int REQUIRED_PARMS = 3; int numTasks = 0; int maxTaskTime = 0; int port = 0; boolean verbose = false; /* process command-line arguments */ if (args.length < REQUIRED_PARMS) { System.err.println(usageMessage); System.exit(1); } try { numTasks = Integer.parseInt(args[0]); maxTaskTime = Integer.parseInt(args[1]); port = Integer.parseInt(args[2]); } catch (NumberFormatException e) { System.err.println(usageMessage); System.exit(1); } if (args.length > REQUIRED_PARMS) { if (args[REQUIRED_PARMS].equals("--verbose")) verbose = true; else { System.err.println(usageMessage); System.exit(1); } } /* do processing */ new Master2( numTasks, maxTaskTime, port, verbose).doProcessing(); } /** Constructor. */ public Master2(int _numTasks, int _maxTaskTime, int _port, boolean _verbose) { super(_numTasks, _maxTaskTime, _port, _verbose); } /** Do processing. */ public void doProcessing() { initialize(); /* build queue of tasks */ buildTaskQueue(numTasks, maxTaskTime); /* start thread to accept connections from other workers */ Thread serverSocketThread = new Thread(new Runnable() { public void run() { try { /* create server socket */ serverSocket = new ServerSocket(port); if (verbose) { System.out.println("waiting for workers"); } /* * accept connections until main thread closes serverSocket * * TODO: figure out some nicer way to do this? * there seems to be no easier way to distinguish the * exception generated by a normal shutdown from errors */ while (true) { acceptConnection(); } } /* TODO: improve error handling? */ catch (IOException e) { if (serverSocketShutDownOnEmptyQueue) { if (verbose) { System.out.println("server socket closed"); } } else { System.err.println("error with server socket:\n\t" + e); System.exit(1); } } } }); serverSocketThread.start(); /* wait for task queue to become empty */ if (verbose) { System.out.println("waiting for task queue to become empty"); } waitUntilTaskQueueEmpty(); /* close server socket to force shutdown of associated thread */ try { serverSocketShutDownOnEmptyQueue = true; serverSocket.close(); } catch (IOException e) { System.err.println("error shutting down server socket:\n\t" + e); } if (verbose) { System.out.println("waiting for server socket thread to finish"); } waitForThreadToComplete(serverSocketThread); /* wait for worker threads to finish */ if (verbose) { System.out.println("waiting for worker threads to finish"); } for (Thread t : workerThreads) { waitForThreadToComplete(t); } /* print result */ System.out.printf( "\nsockets-based distributed client/server version\n"); System.out.printf("number of workers = %d\n", workerThreads.size()); printSummaryInfo(numTasks, maxTaskTime); } private void acceptConnection() throws IOException { Socket s = serverSocket.accept(); synchronized (workerThreads) { int workerID = workerThreads.size(); if (verbose) { System.out.printf("connection from %s, worker %d\n", clientAddress(s), workerID); } Thread w = new Thread(new WorkerTalker(workerID, s)); workerThreads.add(w); w.start(); } } }