/* * Vorlesung "Vernetzte Systeme" WS 1999/2000, Prof. Dr. F. Mattern * ---------------------------------------------------------------- * ClientDispatcherThread.java: * Reads lines from STDIN and dispatches up to individual * ClientSendThreads to send out text blocks of size . * * Required Classes: * - ClientSendThread: * Handle sending and resending (after timeout) of data blocks. Must * be explicitly terminated (using ClientSendThread.terminate()). * - SendBuffer: * Implementation of a Sliding-Window Send-Buffer. * - Packet: * Is used to create String-based Packets, consisting of a (5-digit) * packet ID and a string of up to bytes. * - Timer: * Helps timing how long it takes for sending the file and thus allows * throughput computation. * - SyncPrintWriter: * Allows multiple threads to share a single output stream. * */ import java.io.*; import java.net.*; public class ClientDispatcherThread extends Thread { private SendBuffer sbuf; private Socket serverSocket; private int timeout; private int packetsize = 5; private boolean debug = false; /* Constructor */ public ClientDispatcherThread (SendBuffer sbuf, Socket serverSocket, int timeout, int packetsize, boolean debug) { // Name this thread super ("ClientDispatcherThread"); // copy variables this.sbuf = sbuf; this.serverSocket = serverSocket; this.timeout = timeout; this.packetsize = packetsize; this.debug = debug; } /* print debug messages (if debug is enabled) */ private void msg (String s) { if (debug) System.err.println(s); } /* Dispatch a new ClientSendThread object to send contents of "in" */ public int sendpacket(String in, SyncPrintWriter out) { ClientSendThread c = new ClientSendThread(out, timeout, debug); msg ("Getting next Seq.Nr.: "+ sbuf.show()); // we store a handle to the SendThread in our SendBuffer-Slot! // see SlidingWindowSender.listen() method int s = sbuf.getnextsequencenumber(c); Packet p = new Packet (s, in); // prepare ClientSendThread object c.setoutput(p.asString()); // start ClientSendThread object, which sends the data and then // sleeps milliseconds before attempting again. msg ("Received ["+s+"], starting timeout obj"); c.start(); // On SunOS we need to explicitly give up control once in a while yield(); return s; } /* read from STDIN (in blocks of ) and send data off. * this method gets executed if someone calls * ClientDispatcherThread.start() */ public void run() { try { int bytesRead; char[] cbuf = new char[packetsize]; int lastSequenceNumber = -1; long byteCounter = 0; Timer timer = new Timer(); // helps us count the milliseconds // get an input stream from STDIN BufferedReader standard_in = new BufferedReader( new InputStreamReader(System.in)); // this needs to be synch'ed since timeouts might force // retransmissions, which means that multiple ClientSendThreads might // attempt to send their data through this at the same time! SyncPrintWriter out = new SyncPrintWriter(serverSocket.getOutputStream(), true); timer.start(); // read the data from STDIN in -byte blocks while (((bytesRead = standard_in.read(cbuf,0,packetsize)) >= 0) && // to prevent our sequence numbers from overflowing: (lastSequenceNumber < Integer.MAX_VALUE) ){ msg ("Reading " + bytesRead + " from STDIN"); byteCounter = byteCounter + bytesRead; // for bookkeeping lastSequenceNumber = sendpacket(String.valueOf(cbuf, 0, bytesRead), out); } if (lastSequenceNumber == Integer.MAX_VALUE) { msg ("ClientSendThread: Max Sequence Number reached. Aborting."); } else { msg ("ClientSendThread: No more lines to read"); } // now that we sent all of our data, wait until all ack's are in sbuf.waituntilempty(); // then we can stop the timer timer.stop(); msg ("ClientSendThread: All packets have arrived"); /* do some statistics */ System.err.println ("Bytes read: "+ byteCounter); System.err.println ("Transmission time : "+ timer.runTime() + " ms"); long throughput = (byteCounter*1000) / timer.runTime(); System.err.println ("Throughput (bytes/s): "+ throughput); // clean up out.close(); serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } }