import java.io.*;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.text.DecimalFormat;

public class Client {



    static double difference=0;
    static int totalTransferred=0;
    static StartTime timer;
    static double previousTimeElapsed=0;
    static int sizeDifference=0;
    static int previousSize=0;

    public static void main(String args[]) throws Exception {

        final int lossRate = Integer.parseInt(args[0]);
        final String hostName = args[1];
        final int port = Integer.parseInt(args[2]);
        final String fileName = args[3];
        setUp(hostName, port, fileName);
    }

    public static void setUp(String hostName, int port, String fileName) throws IOException {

        System.out.println("Sending the file");
        //Socket, address and file creation and set up
        DatagramSocket socket = new DatagramSocket();
        InetAddress address = InetAddress.getByName(hostName);
        File file = new File(fileName); 
        // Create a byte array to store file
        InputStream inFromFile = new FileInputStream(file);
        byte[] fileByteArray = new byte[(int)file.length()];
        inFromFile.read(fileByteArray);
        // Start timer
        StartTime timer = new StartTime(0);
        // Create the flag to indicate the very last message in the sequence so transmission 
        // can finally halt 
        int sequenceNumber = 0;
        boolean lastMessageFlag = false;
        // Sequence number for acknowledged packets
        int ackSequenceNumber = 0;
        // Create a counter for number of re-transmissions
        int retransmissionCounter = 0;
        // For as each message we will create
        for (int i=0; i < fileByteArray.length; i = i+1021 ) {

            // Increment sequence number
            sequenceNumber += 1;

            // Create message
            byte[] message = new byte[1024];

            // Set the first and second bytes of the message to the sequence number
            message[0] = (byte)(sequenceNumber >> 8);
            message[1] = (byte)(sequenceNumber);

            // Set flag to 1 if packet is last packet and store it in third byte of header
            if ((i+1021) >= fileByteArray.length) {
                lastMessageFlag = true;
                message[2] = (byte)(1);
            } else { // If not last message store flag as 0
                lastMessageFlag = false;
                message[2] = (byte)(0);
            }

            // Copy the bytes for the message to the message array
            if (!lastMessageFlag) {
                for (int j=0; j <= 1020; j++) {
                    message[j+3] = fileByteArray[i+j];
                }
            }
            else if (lastMessageFlag) { // If it is the last message
                for (int j=0;  j < (fileByteArray.length - i)  ;j++) {
                    message[j+3] = fileByteArray[i+j];          
                }
            }

            // Send the message
            DatagramPacket sendPacket = new DatagramPacket(message, message.length, address, port);

            socket.send(sendPacket);

           totalTransferred=sendPacket.getLength()+totalTransferred;
           totalTransferred = Math.round(totalTransferred);

           if(Math.round(totalTransferred/1000)% 50==0)
              {
                  System.out.println("");
                  System.out.println("");
                  System.out.println("Milestone Statistics");
                  sizeDifference = totalTransferred/1000-previousSize;
                  System.out.println("We just transferred another: " + sizeDifference);
                  difference = timer.getTimeElapsed()-previousTimeElapsed;
                  System.out.println("You have now transferred "+Math.round(totalTransferred/1000)+"Mb");
                  System.out.println("Time taken so far: "+timer.getTimeElapsed());
                  previousTimeElapsed= timer.getTimeElapsed();
                  previousSize=totalTransferred/1000;
                  double throughput = totalTransferred/1000/timer.getTimeElapsed();
                  System.out.println("Throughput average so far :"+throughput);
                  System.out.println("Throughput for last 50: " + sizeDifference/difference);
                  System.out.println("");
                  System.out.println("");
              }




            System.out.println("Sent: Sequence number = " + sequenceNumber + ", Ack Problem? = " + lastMessageFlag);

            // For verifying the the packet 
            boolean ackRecievedCorrect = false;
            boolean ackPacketReceived = false;

            //The acknowledgment is not correct 
            while (!ackRecievedCorrect) {
                // Create another packet by setting a byte array and creating data gram packet
                byte[] ack = new byte[2];
                DatagramPacket ackpack = new DatagramPacket(ack, ack.length);

                try {
                    //set the socket timeout for the packet acknowledgment
                    socket.setSoTimeout(50);
                    socket.receive(ackpack);
                    ackSequenceNumber = ((ack[0] & 0xff) << 8) + (ack[1] & 0xff);
                    ackPacketReceived = true;

                    double time = timer.getTimeElapsed();
                    System.out.println(time);
                }
                catch (SocketTimeoutException e)
                {
                    System.out.println("Socket timed out waiting for the ");
                    ackPacketReceived = false;
                }

                // Break if there is an acknowledgment next packet can be sent
                if ((ackSequenceNumber == sequenceNumber) && (ackPacketReceived)) 
                {   

                    ackRecievedCorrect = true;
                    System.out.println("Ack received: Sequence Number = " + ackSequenceNumber);
                    break;


                }

                // Re send the packet
                else
                { 
                    socket.send(sendPacket);
                    System.out.println("Resending: Sequence Number = " + sequenceNumber);
                    // Increment retransmission counter
                    retransmissionCounter += 1;
                }


            }


        }

        //Socket is closed now transmission is complete

        System.out.println("File " + fileName + " has been sent");
        // Calculate statistics

        double fileSizeKB = (fileByteArray.length) / 1024;
        double transferTime = timer.getTimeElapsed() / 1000;
        double fileSizeMB = fileSizeKB/1000;
        double throughput = fileSizeMB/transferTime;



        System.out.println("");
        System.out.println("");
        System.out.println("Statistics of transfer");
        System.out.println("File " + fileName + " has been sent successfully.");
        System.out.println("The size of the File was "+totalTransferred/1000+ " MegaBytes");
        System.out.println("Time for transfer was " +timer.getTimeElapsed()/1000+ " Seconds");
        System.out.printf("Throughput was %.2f MB Per Second\n",+throughput);
        System.out.println("Number of retransmissions: " + retransmissionCounter);  




        String testString ="File Size: "+fileSizeMB+"mb\n"+"Throughput: "+throughput
                +"\nTotal transfer time: "+transferTime;
        byte[] bytesData = new byte[1024];
        bytesData = testString.getBytes();
        DatagramPacket statPacket = new DatagramPacket(bytesData,bytesData.length,address,port);
        socket.send(statPacket);


        socket.close();
    }






}

What is the easiest way of making this program a thread. So I implement, thread, and can create a new thread of this class from the server on connection, leading eventually to multiple threads. How easy would it be to do this?

Wrap the code in a no-args method, eg

public static void doMyStuff() { ...

then

new Thread(Client::doMyStuff).start();

Easy or what?

ps: I don't like seeing all that in static methods, but that's another question. You will presumably need multiple instances of the class (different instance variable values) for your multiple threads. In which case doMyStuff should not be static, and you can start the Thread like this:

Client c = new Client(...
new Thread(c::doMyStuff).start();

Edited 1 Year Ago by JamesCherrill

This article has been dead for over six months. Start a new discussion instead.