0

最近、標準の TCP ソケットを介したファイル転送用の単純なクライアント サーバー プログラムを作成しました。平均スループットは、WiFi チャネルで約 2.2Mbps でした。私の質問は次のとおりです。各ストリームが同じファイルのいくつかの部分を並行して転送できるように、複数のデータ IO ストリームを介して大きなファイル (5 GB など) を転送することは可能ですか (この目的のために異なるスレッドを使用できます)。これらのファイル部分は、受信側で再組み立てできます。小さなファイルを分割して、dataoutputstream 経由で転送しようとしました。最初のセグメントは正常に動作しますが、ファイル入力ストリームを選択的に読み取る方法がわかりません (選択的な読み取りのために mark() および reset() メソッドも試しましたが、使用しませんでした)

これが私のコードです(テスト目的で、出力をfileoutputstreamにリダイレクトしました):

    public static void main(String[] args) {
    // TODO Auto-generated method stub
    final File myFile=new File("/home/evinish/Documents/Android/testPicture.jpg");
    long N=myFile.length();
    try {
        FileInputStream in=new FileInputStream(myFile);
        FileOutputStream f0=new FileOutputStream("/home/evinish/Documents/Android/File1.jpg");
        FileOutputStream f1=new FileOutputStream("/home/evinish/Documents/Android/File2.jpg");
        FileOutputStream f2=new FileOutputStream("/home/evinish/Documents/Android/File3.jpg");

        byte[] buffer=new byte[4096];
        int i=1, noofbytes;
        long acc=0;
        while(acc<=(N/3)) {
            noofbytes=in.read(buffer, 0, 4096);
            f0.write(buffer, 0, noofbytes);
            acc=i*noofbytes;
            i++;
        }
        f0.close();

ファイルの最初のセグメントを取得しました (これは 1 つのスレッドで DataOutputStream にコピーできます)。同時操作のために 3 つのスレッドで 3 つのストリームを使用できるように、N/3 のセグメントでファイルの残りの部分 (N/3 バイトの後) を読み取る方法を提案できますか?

受信側でファイル セグメントをマージするコードは次のとおりです。

    package com.mergefilespackage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class MergeFiles {

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception{
        // TODO Auto-generated method stub
        IOCopier.joinFiles(new File("/home/evinish/Documents/Android/File1.jpg"), new File[] {
            new File("/home/evinish/Documents/Android/File2.jpg"), new File("/home/evinish/Documents/Android/File3.jpg")});
    }
}
class IOCopier {
    public static void joinFiles(File destination, File[] sources)
            throws IOException {
        OutputStream output = null;
        try {
            output = createAppendableStream(destination);
            for (File source : sources) {
                appendFile(output, source);
            }
        } finally {
            IOUtils.closeQuietly(output);
        }
    }

    private static BufferedOutputStream createAppendableStream(File destination)
            throws FileNotFoundException {
        return new BufferedOutputStream(new FileOutputStream(destination, true));
    }

    private static void appendFile(OutputStream output, File source)
            throws IOException {
        InputStream input = null;
        try {
            input = new BufferedInputStream(new FileInputStream(source));
            IOUtils.copy(input, output);
        } finally {
            IOUtils.closeQuietly(input);
        }
    }
}
class IOUtils {
    private static final int BUFFER_SIZE = 1024 * 4;

    public static long copy(InputStream input, OutputStream output)
            throws IOException {
        byte[] buffer = new byte[BUFFER_SIZE];
        long count = 0;
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
            count += n;
        }
        return count;
    }

    public static void closeQuietly(Closeable output) {
        try {
            if (output != null) {
                output.close();
            }
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
}

どんな助けでも大歓迎です!前もって感謝します!

4

2 に答える 2

3

より多くのソケットを使用して、同じリンクを介してこれ以上の速度を得ることはできません。各ソケットは、特定のサイズの特定の数のパケットを送信します。ソケットの数を 2 倍にすると、1 秒あたりのパケット数 * ソケットは半分になり、衝突、オーバーヘッド、および競合のためにさらに減少します。パケットがぶつかったり、ごちゃごちゃしたり、パニックになったりします。OS は失われた ACK の大混乱を処理できず、WiFi カードはそのような速度で送信するのに苦労しています。低レベルの攻撃も失っています。パケットが失われると、絶望的な TCP スタックが送信速度を下げます。信号の改善によりこれが発生する可能性がある場合、愚かなウィンドウ症候群または別の形式の TCP デッドロックにより、低速でスタックします。

より広いキャリア帯域、MiMo、または複数のパスからより高速な速度を得ようとする WiFi の試みは、ソケットが 1 つであっても、すでに利益として実現されています。これ以上先に進むことはできません。

さて、待ってください。私たちはWiFiの速度をかなり下回っていますよね?もちろん、バッファリングを使用する必要があります!

ソケットの getInputStream または getOutputStream メソッドから BufferedWriter および BufferedReader オブジェクトを作成していることを確認してください。次に、それらのバッファへの書き込み/読み取りを行います。速度が多少向上する場合があります。

于 2013-07-15T19:32:29.880 に答える
0

のバイト配列を取得して、FileInputStream10 KB ごと (10.000 バイトごと) に分割できます。次に、ストリームを介してこれらのパーツを順番に送信します。

サーバー上で配列を再びまとめて、この巨大なバイト配列からファイルを読み取ることができます。

于 2013-07-15T19:32:21.787 に答える