0

I am trying to upload a file on a server and display how many bytes are uploaded per second by this way:

public void RunUploadTest () {
    try {
        URL url = new URL(serverLink);

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("content-type", "video/mp4");

        for(int i =0; i<10; i++) {
            FileInputStream fis = new FileInputStream(myFileVideo);
            DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
            int bytesWrite = 0;
            byte[] buffer = new byte[512];
            Stopwatch timer = new Stopwatch();
            int read;
            while ((read = fis.read(buffer)) != -1&& timer.elapsedTime()<1000) {
                dos.write(buffer, 0, read);
                dos.flush();
                bytesWrite++;
            }
            Log.d("Upload", "Bytes written: " + bytesWrite*512);
        }
        fis.close();

    } catch (IOException e){
        e.printStackTrace();
    }
}

The problem is that is not calculating how many bytes are uploaded as I expect. Do you have any idea why is not working?

CDspace
  • 2,639
  • 18
  • 30
  • 36

2 Answers2

1

If you have 10 times the same bytes written, there are 2 options:

  1. your file is written in less than 1 second;
  2. your elapsedTime method, returns in seconds(for example) and not in milliseconds

You probably don't need that for loop too, it makes you read the file 10 times.

I would rewrite your code like this:

public void RunUploadTest () {
    try {
        URL url = new URL(serverLink);

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("content-type", "video/mp4");

        FileInputStream fis = new FileInputStream(myFileVideo);
        DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
        int bytesWrite = 0;
        byte[] buffer = new byte[512];
        int read;
        while((read = fis.read(buffer))) {
            Stopwatch timer = new Stopwatch();
            while (timer.elapsedTime()<1) { //my guess here is that this method returns in seconds
                dos.write(buffer, 0, read);
                dos.flush();
                bytesWrite += read; //taken from Yoni Gross answer
            }
            Log.d("Upload", "Bytes written: " + bytesWrite);
        }
        fis.close();

    } catch (IOException e){
        e.printStackTrace();
    }
}
ths
  • 11
  • 5
  • public Stopwatch() { start = System.currentTimeMillis(); } //Returns the elapsed time (in milliseconds) since the stopwatch was created public int elapsedTime() { long now = System.currentTimeMillis(); return (int) (now - start); } – Federica Marini Feb 24 '17 at 14:27
  • that is my Stopwatch code. It is all in milliseconds. And about the for loop, I neet to get the average of bytes uploaded in 10 different times. – Federica Marini Feb 24 '17 at 14:32
  • What is the size of your file? I tested your code(I should have done it before), and only start having different values with files greater than 32420864 bytes(~=30Mb) – ths Feb 24 '17 at 16:55
  • I have tested wit a bigger file but I get the error: java.lang.OutOfMemoryError about the line dos.write(buffer, 0, read). – Federica Marini Feb 25 '17 at 11:31
  • Apart from this, I find very strange that it is able to upload 30 MB per second for both of us in every moment we try it: the number of bytes sent, is a parameter that depends on the network. It should change depending on whether the test is performed: for example on wifi or mobile network @ths – Federica Marini Feb 25 '17 at 11:39
0

There are few problems with your code:

1. You are not counting right

This is a relatively minor issue, but the last buffer you read/write will probably not going to be 512 bytes long, so your calculation will not be precise.

you should change

    bytesWrite++;
}
Log.d("Upload", "Bytes written: " + bytesWrite*512);

to

    bytesWrite += read;
}
Log.d("Upload", "Bytes written: " + bytesWrite);

2. You are stopping the upload after 1 second anyway

The following condition:

while ((read = fis.read(buffer)) != -1&& timer.elapsedTime()<1000)

Will stop either when the file has finished reading, or 1 second elapsed. Unless a very small file, most likely file upload will stop after 1 second.

I'm not completely sure if you want an update every second, or just the average.

In case of average you should just change the while condition to:

while (read = fis.read(buffer))

And change log to:

float uploadRate = (float)(bytesWrite / timer.elapsedTime()) / 1000.0f;
String logString = String.format("Upload rate: %.2f bytes per second", uploadRate)
Log.d("Upload", logString);

In case you do want to print progress every second, you'll need to do something more fancy and expensive, like:

while (read = fis.read(buffer)) {
    dos.write(buffer, 0, read);
    dos.flush();
    bytesWrite += read;
    if (timer.shouldPrintSecondsProgress(){
        Log.d("Upload", "Bytes written: " + bytesWrite);
    }
}

StopWatch.shouldPrintSecondsProgress should be something like:

public boolean shouldPrintSecondsProgress(){
    int currentSecond = elapsedTime() / 1000;
    if (currentSecond == nextUpdate){ //I've ignored the > case, which is probably an error in our case
        nextUpdate++; //this is an int field, marking the next second cause update
        return true;
    }
    return false;
}

3. It's possible you measure only 'send' and not 'upload'

While you are sending all your data and flushing the request stream, some layer of the networking stack might have buffer/async behavior. Actually the roundtrip alone might effect calculation correctness.

It best if you close the output stream prior to measure time elapsed, and/or read the response from server (which will ensure upload is finished).

Yoni Gross
  • 816
  • 8
  • 16
  • I have tried but the result is the same. Anyway as I have understeand the method "write" writes "read" bytes in a buffer from the offset 0. My buffer is 512 bytes big, that is why I wrote only "Byteswrite++" – Federica Marini Feb 24 '17 at 14:18
  • @FedericaMarini you are right, I haven't noticed. Yet, it is not correct. In addition, I've edited to include other problems in your code. – Yoni Gross Feb 26 '17 at 17:54