0

ファイル転送を再開すると奇妙な現象が発生します。

下の写真を見ると、悪い部分が見えます。

これは明らかにランダムに、おそらく 10 回ごとに発生します。
Androidフォンからftp経由でJavaサーバーに写真を送信しています。

私がここで忘れたことは何ですか。 The transfer is resumed like this が
原因で接続が切断されていることがわかります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++;

    }
4

2 に答える 2

2

エラーを見つけました、そして、問題は私の部分からの悪い論理でした。もうこれ以上言わない。

送信する直前にサイズ変更された画像を送信していました。

問題は、転送に失敗した後に履歴書が開始されたときに
、サイズ変更された画像が使用されず、代わりに、コード
がより大きなスケールサイズの元の画像を使用したことでした。

サイズ変更された一時的な画像を保持する短期間のキャッシュを設定しました。

アプリの作成が複雑であることに照らして、再開中のファイルが元のファイルと同じではないことを単に忘れました。

于 2012-01-23T22:59:44.013 に答える
2

BufferedOutputStream、BufferedInputStreamを使用する場合は、次の点に注意する必要があります。

  1. BuffererdInputStreamの前にBufferedOutputStreamを作成します(クライアントとサーバーの両方で)
  2. そして、作成直後にフラッシュします。
  3. 書き込みのたびにフラッシュします(閉じる直前ではありません)

それは私のために働いた。

編集済み

パケットペイロードにsentRequestTime、receivedRequestTime、sentResponseTime、receivedResponseTimeを追加します。これらでSystem.nanoTime()を使用し、サーバーとクライアントを同じホストで実行し、ExecutorServiceを使用してそのサーバーの複数のクライアントを実行し、要求パケットと応答パケットの両方の(受信-送信)、Excelチャートの時間遅延をプロットします(いくつかのcsv形式)。これは、bufferedIOStreamの前とafterIOStreamで行います。パフォーマンスが100%向上したことを知って喜ぶでしょう。そのグラフをプロットするのはとてもうれしく、約45分かかりました。

また、カスタムバッファを使用すると、パフォーマンスがさらに向上すると聞いています。

再度編集オブジェクトIOStreamsを使用している場合、4つの長い変数のペイロードをオブジェクトに追加し、クライアントからパケットを送信するときにsentRequestTimeを初期化し、サーバーが応答を受信するときにreceivedRequestTimeを初期化します。サーバーからクライアントへの応答も。次に、受信時間と送信時間の違いを見つけて、応答と要求の遅延を調べます。ローカルホストでこのテストを実行するように注意してください。異なるハードウェア/デバイス間で実行すると、実際の時間差がテスト結果に干渉する可能性があります。requestReceivedTimeはサーバー側でタイムスタンプが付けられ、requestSentTimeはクライアント側でタイムスタンプが付けられるためです。言い換えれば、彼ら自身の現地時間は(明らかに)刻印されています。そして、これらのデバイスの両方がナノ秒まで正確に同時に実行されることは不可能です。少なくとも異なるデバイス間で実行する必要がある場合は、ntpが実行されていることを確認してください(時間の同期を保つため)。とは言うものの、bufferedioの前後のパフォーマンスを比較しているので(実際の時間遅延は気にしないのですか?)、時間のずれはそれほど重要ではありません。バッファリング前とバッファリング後の一連の結果を比較することが実際の関心事です。

楽しみ!!!

于 2012-01-24T12:13:04.033 に答える