/** * 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, seed, 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. */ package csci3366.sample.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; import csci3366.sample.masterworker.sockets.Master; 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 seed portNum [--verbose]"; int numTasks = 0; int maxTaskTime = 0; int seed = 0; int port = 0; boolean verbose = false; /* process command-line arguments */ if (args.length < 4) { System.err.println(usageMessage); System.exit(1); } try { numTasks = Integer.parseInt(args[0]); maxTaskTime = Integer.parseInt(args[1]); seed = Integer.parseInt(args[2]); port = Integer.parseInt(args[3]); } catch (NumberFormatException e) { System.err.println(usageMessage); System.exit(1); } if (args.length > 4) { if (args[4].equals("--verbose")) verbose = true; else { System.err.println(usageMessage); System.exit(1); } } /* do processing */ new Master2( numTasks, maxTaskTime, seed, port, verbose).doProcessing(); } /** Constructor. */ public Master2(int numTasks_, int maxTaskTime_, int seed_, int port_, boolean verbose_) { super(numTasks_, maxTaskTime_, seed_, port_, verbose_); } /** Do processing. */ public void doProcessing() { initialize(); /* build queue of tasks */ buildTaskQueue(numTasks, maxTaskTime, seed); /* 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 * * FIXME?: 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(); } } /* FIXME?: 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(); } } }