/* * Vorlesung "Vernetzte Systeme" WS 1999/2000, Prof. Dr. F. Mattern * ---------------------------------------------------------------- * SlidingWindowSender.java: * Textfile-Sender using Sliding Window Protocol. * * Required Classes: * - ClientDispatcherThread: * Reads lines from STDIN and dispatches up to individual * ClientSendThreads to send out text blocks of size . * - SendBuffer: * Implementation of a Sliding-Window Send-Buffer. * */ import java.net.*; import java.io.*; public class SlidingWindowSender { /* fixed constant */ private final static int MAXBUFFERSIZE = 25; /* = threads! */ /* these aren't really constants, they can be overriden on commandline */ private static int BUFFERSIZE = 5; private static int TIMEOUT = 2000; // in milliseconds private static int PACKETSIZE = 100; // in bytes private static SendBuffer sbuf; private static boolean debug = false; /* show debug message (if debugging is enabled) */ private static void msg (String s) { if (debug) System.err.println(s); } private static void showUsage() { System.err.println("Usage: java SlidingWindowSender "+ " [debug]"); System.err.println(" : send-window size. Default is "+ BUFFERSIZE); System.err.println(" : timeout for retransmission (in ms)"+ ". Default is " + TIMEOUT + " ms"); System.err.println(" : packetsize in bytes. Default is "+ PACKETSIZE + " bytes"); } private static void showSettings() { System.err.println ("Sender initialized:"); System.err.println (" Window size: " + BUFFERSIZE); System.err.println (" Timeout : " + TIMEOUT+" ms"); System.err.println (" Packetsize : " + PACKETSIZE+" bytes"); System.err.println ("\nReading data from STDIN...\n"); } /* very simple way to parse the commandline args */ private static void parseArgs(String[] args) { try { if (args.length > 0) BUFFERSIZE = Integer.parseInt(args[0]); if (args.length > 1) TIMEOUT = Integer.parseInt(args[1]); if (args.length > 2) PACKETSIZE = Integer.parseInt(args[2]); if (args.length > 3) debug = true; } catch (NumberFormatException e) { showUsage(); System.exit(-1); } if (BUFFERSIZE>MAXBUFFERSIZE) { System.err.println ("The maximum Buffer Size is "+ MAXBUFFERSIZE + ". Setting Buffer to upper Limit."); BUFFERSIZE = MAXBUFFERSIZE; } showSettings(); } /* handle incoming data on the socket (i.e. ACK's) */ public static void recvack (int s) { ClientSendThread c; msg("Receiving ACK["+s+"]"); // simple principle: in order to get a handle to the ClientSendThread // that sent this packet (and will try to retransmit it if it wakes // up from its milliseconds of sleep!) we saved a reference // in the corresponding send-buffer slot. All we need to do now is // read out that slot and then call the thread's terminate() method. if ((c = (ClientSendThread)sbuf.getpacket(s)) != null) { c.terminate(); // terminate corresponding timeout-thread sbuf.ackpacket(s); // clear buffer & delete timeout object } else { // there's no object reference at this slot position anymore, // we must have already acknowledged that packet } msg("Done ACK["+s+"]"); } /* this loops over the input stream of our socket and waits for ACK's. * Since at some point all ACK's are in, we have to check to see if * the ClientDispatcherThread is still alive, otherwise we won't notice! */ private static void listen (BufferedReader in, ClientDispatcherThread Dispatcher) { /* Start Listening here */ try { String inputLine; while (Dispatcher.isAlive()) { if (in.ready()) { inputLine = in.readLine(); msg ("< ACK_"+ inputLine); // translate string "000103" into integer 103 // this might break if we get broken ACK's, no? int ack_id = Integer.valueOf(inputLine).intValue(); if (ack_id >= 0) { recvack(ack_id); } } } } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { /* read command-line args and show help/current settings */ parseArgs(args); /* Get forwarding info from args */ int serverPort = 4444; /* for now let's use a fixed address */ String serverHost = "localhost"; /* Open Socket */ Socket serverSocket = null; try { serverSocket = new Socket(serverHost, serverPort); } catch (IOException e) { msg("Opening Server Address failed."); System.exit(1); } /* Open IO-Streams */ BufferedReader in = new BufferedReader(new InputStreamReader( serverSocket.getInputStream())); /* create sendbuffer */ sbuf = new SendBuffer(BUFFERSIZE); msg("Initializing buffer: "+ sbuf.show()); /* Start an extra thread for Dispatching our SendThreads */ ClientDispatcherThread Dispatcher = new ClientDispatcherThread (sbuf, serverSocket, TIMEOUT, PACKETSIZE, debug); /* Start reading file and dispatch SendThreads (in the background) */ Dispatcher.start(); /* At the same time: Listen for ACK's */ listen(in, Dispatcher); // the listen() method only returns if the dispatcher is done. // the dispatcher is only done if all is read & sent, and all // ACK's are in. So we're done! msg("Client: Done!"); serverSocket.close(); } }