1

nio ServerSocketChannel と SocketChannel を使用して、クライアントとサーバー間で大きなファイルを転送しています。問題は、サイズ 6060064 バイトのファイルを送信者から受信者に転送すると、受信者は 6059040 バイトしか受信せず、一部のバイトが欠落していることです。欠落バイトの差分ギャップが増加します。これらのバイトが欠落している理由がわかりません。

送信者コード:

public boolean send(SelectionKey selectionKey) {

    File file = new File("/media/data1/sample.mp4");
    try {
        SocketChannel socketChannel = (SocketChannel) selectionKey
                .channel();
        FileInputStream fileInputStream = new FileInputStream(file);
        System.out.println("File Length :: " + file.length());
        System.out.println("File lastModified :: " + file.lastModified());

        FileChannel fileChannel = fileInputStream.getChannel();

        transfer(fileChannel, socketChannel, file.length(), 1024 * 50);

        fileInputStream.close();

        System.out.println("File Send Completely Done 100%....");
        System.out.println("Closing Connection 100%....");

        return true;

    } catch (Exception e) {
        System.out.println(e);
        System.out.println("Connection Failed. Connectiontimeout.");
        return false;
    }
}

public static void transfer(FileChannel fileChannel,
        SocketChannel socketChannel, long lengthInBytes,
        long chunckSizeInBytes)
        throws IOException {

    long overallBytesTransfered = 0L;
    long time = -System.currentTimeMillis();
    
    while (overallBytesTransfered < lengthInBytes) {

        long bytesTransfered = 0L;

        bytesTransfered = fileChannel.transferTo(
                overallBytesTransfered,
                Math.min(chunckSizeInBytes, lengthInBytes
                        - overallBytesTransfered), socketChannel);

        System.out.println("bytesTransfered :: " + bytesTransfered);

        overallBytesTransfered += bytesTransfered;

        System.out.printf(
                "overall bytes transfered: %s progress %s%%\n",
                overallBytesTransfered, Math.round(overallBytesTransfered / ((double) lengthInBytes) * 100.0));
    }

    time += System.currentTimeMillis();

    System.out.printf("Transfered: %s bytes in: %s s -> %s kbytes/s\n",
                overallBytesTransfered, time / 1000,
                (overallBytesTransfered / 1024.0) / (time / 1000.0));
    System.out.println("------- File transfer completed ------");

}

受信者コード:

public boolean recieve(SelectionKey key) {
    SocketChannel socketChannel = null;
    Socket socket = null;

    try {
        socketChannel = (SocketChannel) key.channel();
        socket = socketChannel.socket();
        System.out.println(socketChannel.getRemoteAddress());

        // Save file destination
        String FileKey = "/media/data1/Test/sample1.mp4";
        // File size
        long sizeInBytes = 6060064;
        
        long timeStap = 1402301850000l;

        File file = new File(FileKey);
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        FileChannel fileChannel = fileOutputStream.getChannel();

        transfer(fileChannel, socketChannel, sizeInBytes, 1024 * 100);

        fileOutputStream.close();

        file.setLastModified(timeStap);
        socket.close();
        return true;

    } catch (Exception e) {
        System.out.println("Connection Failed. Connectiontimeout.");
        e.printStackTrace();
        return false;
    }
}

public static void transfer(FileChannel fileChannel,
        SocketChannel socketChannel, long lengthInBytes, long chunckSizeInBytes)
        throws IOException {

    long overallBytesTransfered = 0L;
    long time = -System.currentTimeMillis();
    while (overallBytesTransfered < lengthInBytes) {
        
        long bytesTransfered = 0L;

        bytesTransfered = fileChannel.transferFrom(
                socketChannel,
                overallBytesTransfered,
                Math.min(chunckSizeInBytes, lengthInBytes
                        - overallBytesTransfered));

        System.out.println("bytesTransfered :: " + bytesTransfered);

        overallBytesTransfered += bytesTransfered;

        System.out.printf(
                "overall bytes transfered: %s progress %s%%\n", overallBytesTransfered,
                Math.round(overallBytesTransfered / ((double) lengthInBytes) * 100.0));

    }
    
    time += System.currentTimeMillis();

        System.out.printf("Transfered: %s bytes in: %s s -> %s kbytes/s\n",
                overallBytesTransfered, time / 1000,
                (overallBytesTransfered / 1024.0) / (time / 1000.0));
        System.out.println("-------Dateiübertragung fertig------");

}

送信者の出力:

bytesTransfered :: 18464

転送された全体のバイト数: 6060064 進行状況 100%

転送: 6060064 バイト: 119 秒 -> 49.67708595651809 キロバイト/秒

受信機の出力:

バイト転送:: 0

転送された全体のバイト数: 6059040 進行状況 100%

ファイルのサイズが 6059040 バイトに増加している間、受信側の while ループはプロセスを手動で停止するまで続き、bytesTransferedは常に受信側でゼロを返します。

これらのバイトが欠落している理由を誰か教えてください。

4

1 に答える 1

-1

JDK7u60 でも同じことが見られます (以前はられませんでした) 。

バッファーが約 200KB を超えると、レシーバーがソケットを読み取る前に SocketChannel が閉じられることに注意してください。

これまでの唯一の提案は、一時停止して書き込みを抑制することです

int bytes = socketChannel.write(currentWriteBuffer);
if (bytes > 200000) {
    try {
        Thread.sleep(100 * (bytes / 200000));
    }
    catch (InterruptedException e) {
      // ignore 
    }
}

実際の制限や実際の遅延についてはまだ調べていませんが、これでうまくいきました。より良い回答を調査しているときに、あなたの質問を見つけたことに注意してください。

于 2014-07-09T00:43:37.360 に答える