Android на компьютер FTP возобновляет загрузку странное явление

У меня странное явление при возобновлении передачи файлов.

Посмотрите на картинку ниже, вы видите плохой участок.

Это происходит, по-видимому, случайным образом, может быть, каждый 10-й раз.
Я отправляю изображение со своего телефона Android на java-сервер по ftp.

Что я тут забыл.
Я вижу, что соединение прервано из-за java.net.SocketTimeoutException:
Передача возобновляется вот так

Resume at : 287609 Sending 976 bytes more

Байты всегда правильные, когда файл полностью получен. Даже для картинки ниже.

Не знаю, с чего начать отладку, так как в большинстве случаев он работает.

Любые предложения или идеи были бы благодарны, я думаю, что полностью пропустил что-то здесь.

введите здесь описание изображения

Код отправителя устройства (только цикл отправки):

int count = 1;    
  //Sending N files, looping N times
  while(count <= max) {        
    String sPath = batchFiles.get(count-1);

    fis = new FileInputStream(new File(sPath));

    int fileSize =  bis.available();

    out.writeInt(fileSize); // size

    String nextReply = in.readUTF();
    // if the file exist,
    if(nextReply.equals(Consts.SERVER_give_me_next)){
        count++;                        
        continue;
    }
    long resumeLong = 0; // skip this many bytes 
    int val = 0;
    buffer = new byte[1024];

    if(nextReply.equals(Consts.SERVER_file_exist)){
        resumeLong = in.readLong();
    }

    //UPDATE FOR @Justin Breitfeller, Thanks
    long skiip = bis.skip(resumeLong);
if(resumeLong != -1){
   if(!(resumeLong == skiip)){
      Log.d(TAG, "ERROR skip is not the same as resumeLong ");
      skiip = bis.skip(resumeLong);
      if(!(resumeLong == skiip)){
        Log.d(TAG, "ERROR ABORTING skip is not the same as resumeLong);
        return;
      }
  }
    }

    while ((val = bis.read(buffer, 0, 1024)) > 0) {
        out.write(buffer, 0, val);
        fileSize -= val;
            if (fileSize < 1024) {
            val = (int) fileSize;
        }

    }

    reply = in.readUTF();
    if (reply.equals(Consts.SERVER_file_receieved_ok)) {
        // check if all files are sent
        if(count == max){
           break;
        }
    }
    count++;



   }

Код приемника (очень урезанный):

     //receiving N files, looping N times
    while(count < totalNrOfFiles){

        int ii = in.readInt(); // File size
        fileSize = (long)ii;

        String filePath = Consts.SERVER_DRIVE + Consts.PTPP_FILETRANSFER;
        filePath = filePath.concat(theBatch.getFileName(count));
        File path = new File(filePath);
        boolean resume = false;

        //if the file exist. Skip if done or resume if not
        if(path.exists()){
            if(path.length() == fileSize){ // Does the file has same size
                logger.info("File size same skipping file:" +                            theBatch.getFileName(count) );
                count++;
                out.writeUTF(Consts.SERVER_give_me_next);
                continue;   // file is OK don't upload it again
            }else { 
                // Resume the upload
                out.writeUTF(Consts.SERVER_file_exist); 
                out.writeLong(path.length());
                resume = true;
                fileSize = fileSize-path.length();
                logger.info("Resume at : " + path.length() + 
" Sending "+ fileSize +" bytes more");

            }
        }else
            out.writeUTF("lets go");


        byte[] buffer = new byte[1024];
        // ***********************************
        //  RECEIVE FROM PHONE
        // ***********************************

        int size = 1024;
        int val = 0;

        bos = new BufferedOutputStream(new FileOutputStream(path,resume));

        if(fileSize < size){
            size = (int) fileSize;
        }

        while (fileSize >0) {
            val = in.read(buffer, 0, size);
            bos.write(buffer, 0, val);
            fileSize -= val;
            if (fileSize < size)
                size = (int) fileSize;
        }
        bos.flush();
        bos.close();
        out.writeUTF("file received ok");

        count++;

    }

person Erik    schedule 15.01.2012    source источник
comment
Может ли это быть потому, что я установил длинное резюмеLong = 0; Может должно быть -1   -  person Erik    schedule 15.01.2012
comment
Ваш код может использовать некоторые комментарии. Попробуйте заставить отправителя разорвать соединение, скажем, с каждым другим файлом, и посмотрите, что сделает получатель.   -  person Reuben Scratton    schedule 19.01.2012
comment
Это то, что я делаю, чтобы проверить это. убивая соединение всеми возможными способами, но я не могу воспроизвести его таким образом. (это происходит, когда это происходит) Это похоже на устройство, при отправке код устройства BufferedInputStream.skip пропускает нормально, но все же какая-то цифра неверна. Размер всегда соответствует размеру файла после завершения загрузки. У меня около 200 устройств по всему миру, использующих мое приложение, и на некоторых из них возникают проблемы. Может быть, это что-то конкретное устройство портит ситуацию.   -  person Erik    schedule 19.01.2012


Ответы (2)


Нашел ошибку, и проблема заключалась в плохой логике с моей стороны. больше ни слова.

Я отправлял фотографии, размер которых изменялся непосредственно перед отправкой.

Проблема заключалась в том, что когда возобновление запускалось после неудачной передачи,
изображение с измененным размером не использовалось, вместо этого код использовал исходное
изображение, которое имело больший масштаб.

Теперь я настроил недолговечный кеш, в котором хранятся временные изображения измененного размера.

В свете сложности приложения, которое я делаю, я просто забыл, что файлы во время возобновления не совпадают с исходными.

person Erik    schedule 23.01.2012
comment
Еще одна вещь, на которую вы, возможно, захотите обратить внимание, это то, что вы не проверяете, что skip() возвращает количество байтов, которые вы хотели пропустить. Некоторые реализации потенциально могут возвращать меньше желаемой суммы (требуется еще один вызов для пропуска для правильной синхронизации вашего потока). - person Justin Breitfeller; 24.01.2012

С BufferedOutputStream, BufferedInputStream вам нужно следить за следующим

  1. Создайте BufferedOutputStream перед BuffererdInputStream (как на клиенте, так и на сервере)
  2. И сбросить сразу после создания.
  3. Сбрасывать после каждой записи (не только перед закрытием)

Это сработало для меня.

Отредактировано

Добавьте sentRequestTime, ReceiveRequestTime, sentResponseTime, ReceivedResponseTime в полезную нагрузку вашего пакета. Используйте для них System.nanoTime(), запустите свой сервер и клиент на одном хосте, используйте ExecutorService для запуска нескольких клиентов для этого сервера и отобразите ваши (полученные-отправленные) пакеты запроса и ответа, временную задержку на диаграмме Excel (некоторый формат CSV). Сделайте это перед буферизованным IOStream и после IOStream. Вам будет приятно узнать, что ваша производительность увеличилась на 100%. Я был очень рад построить этот график, это заняло около 45 минут.

Я также слышал, что использование пользовательского буфера еще больше повышает производительность.

Отредактировано снова. В моем случае я использую Object IOStreams, я добавил к объекту полезную нагрузку из 4 длинных переменных и инициализирую sentRequestTime, когда отправляю пакет от клиента, инициализирую ReceiveRequestTime, когда сервер получает ответ, и так далее для ответ от сервера к клиенту тоже. Затем я нахожу разницу между полученным и отправленным временем, чтобы узнать задержку ответа и запроса. Будьте осторожны, чтобы запустить этот тест на локальном хосте. Если вы запускаете его между разными аппаратными средствами/устройствами, их фактическая разница во времени может повлиять на результаты вашего теста. Поскольку requestReceivedTime имеет отметку времени на стороне сервера, а requestSentTime имеет отметку времени на стороне клиента. Другими словами, их собственное местное время проставлено (очевидно). И оба этих устройства работают в одно и то же время с точностью до наносекунды. Если вы должны запускать его между разными устройствами, по крайней мере, убедитесь, что у вас запущен ntp (чтобы синхронизировать их время). Тем не менее, вы сравниваете производительность до и после буферизации (вас действительно не волнуют фактические задержки, верно?), поэтому временной дрейф не должен иметь большого значения. Сравнение набора результатов до буферизации и после буферизации - ваш реальный интерес.

Наслаждаться!!!

person Siddharth    schedule 24.01.2012
comment
сделал проверку того, где я смываю и заметил, что я пропустил это в одной ситуации. Большое спасибо - person Erik; 26.01.2012
comment
что это за ReceiveResponseTime, какой-нибудь пример? или веб-страницу я могу прочитать? - person Erik; 28.01.2012
comment
отредактировал ответ с дополнительной информацией. Надеюсь, теперь все ясно. Если нет, могу уточнить. Не стейсняйся спросить. Спасибо. - person Siddharth; 28.01.2012