2016-11-22 6 views
0

ファイルをソケットでコピーする最も速い方法はどれですか?私はいくつかの方法を試しましたが、転送とCPU使用に関する最速の方法を見つけたとは確信していません。 (ベストの結果:175mBit /秒(SSD /ギガビット・ネットワーク))ソケットを介してファイルをコピーする最速の方法

サーバー:

ByteBuffer bb = ByteBuffer.allocate(packet_size); 
DataOutputStream data_out = new DataOutputStream(socket.getOutputStream()); 

while(working){ 

    int count =0; 
    int packet_size = in.readInt(); 
    long pos = in.readLong(); 
    if(filechannel.position()!=requested_pos){ 
     filechannel.position(requested_pos); 
    } 
    bb.limit(packet_size); 
    bb.position(0); 
    if((count=filechannel.read(bb))>0){ //FileInputStream.getChannel() 
     data_out.writeInt(count); 
     data_out.write(bb.array(),0,count); 
    }else{ 
    working=false; 
    } 
} 

はクライアント:

for(long i=0;i<=steps;i++){ 

    data_out.writeInt(packet_size);  //requested packet size 
    data_out.writeLong(i*packet_size); //requested file position 

    count=in.readInt(); 
    bb.clear(); 
    bb.limit(count); 

    lastRead=0; 
    while(lastRead<count){ 
     lastRead+=in.read(bytes,lastRead,count-lastRead); 
    } 
    bb.put(bytes,0,count); 
    bb.position(0); 
    filechannel.write(bb); // filechannel over RandomAccessFile 
} 

任意の提案ですか?

+2

ブロックを圧縮し、もう一方の端で解凍することができます。たとえば、すばらしいJavaの試用を試みる – qwr

答えて

0

NIOを使用します。

import java.nio.ByteBuffer; 
    import java.nio.channels.Channels; 
    import java.nio.channels.ReadableByteChannel; 
    import java.nio.channels.WritableByteChannel; 


public class FileServlet extends HttpServlet { 

     @Override 
     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 

      try(final InputStream is = new BufferedInputStream((InputStream) <YOUR INPUT STREAM TO A FILE HERE>); 
       final OutputStream os = new BufferedOutputStream(response.getOutputStream());) { 

       fastCopy(is, os); 
      } 

} 

public static void fastCopy(final InputStream src, final OutputStream dest) throws IOException { 
    fastCopy(Channels.newChannel(src), Channels.newChannel(dest)); 
} 



    public static void fastCopy(final ReadableByteChannel src, final WritableByteChannel dest) throws IOException { 
     final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024); 

     while(src.read(buffer) != -1) { 
      buffer.flip(); 
      dest.write(buffer); 
      buffer.compact(); 
     } 

     buffer.flip(); 

     while(buffer.hasRemaining()) { 
      dest.write(buffer); 
     } 
    }  
} 

} 
+1

JavaのNIOがJavaのIOよりも速いというのは神話です。良い答えです。 – fireandfuel

3

あなたは問題の半分しか見ていません。送信/受信に使用されるコードは、1つの要素に過ぎません。あなたがそれを最適化しても、不適切なパラメータでソケットを設定すると、パフォーマンスが大きな打撃を受けます。

大量のデータ転送を行う場合は、ソケットに十分な大きさのバッファがあることを確認してください。私は少なくとも64kb、おそらくより大きなものを選ぶだろう。送受信バッファは独立して設定することができます。送信側には大(r)送信バッファを、受信側には大(r)受信バッファが必要です。

socket.setReceiveBufferSize(int); 
    socket.setSendBufferSize(int); 
    socket.setTcpNoDelay(false); 

設定TCP は何をやっているを知っているし、あなたを確認した後に本当に絶対にそれを必要としますしない限り、OFFにNO DELAY、。 neverはスループットを向上させますが、これとは逆にスループットを低下させる可能性があります。

次は、そのバッファを維持するために送信者コードを調整することです。完全です。ファイルからの最大速度読み込みとソケットへの書き込みは、2種類の独立したスレッドに分かれて、何らかの種類のキューを使用して互いに通信する必要があります。キュー内のチャンクは、かなり大きい(少なくとも数kb)必要があります。

同様に受信コードは受信バッファをできるだけ空に保つために最善を尽くすべきです。この場合も、最高の速度を得るには、ソケットを読み取るスレッドとデータを処理するスレッドの2つのスレッドが必要です。間に送信者のようにキューイングします。

キューの仕事は、実際のネットワーク転送からのファイル/書き込みからデータへの読み込みを切り離すことです。逆もまた同様です。

上記は伝送チャネルに関係なく最大スループットを得るための一般的なパターンです。遅いチャンネルは完全に飽和状態に保たれます。読み取り/書き込みまたはネットワーク転送のファイルになります。

可能なパフォーマンスの最後の数パーセントを圧縮するようにバッファサイズを調整することができます(ソケットの場合は64kb、キューの最大サイズが8MBのチャンクで開始します)。可能な限り)。

あなたが遭遇する可能性があるもう一つの制限要因は、TCP転送ウィンドウのスケーリング(特に高帯域幅、高レイテンシ接続)です。レシーバが受信バッファをできるだけ早く空にすることを保証することを除いて、あなたがJava側からできることは何もありません。調整オプションはOSレベルに存在します。

+0

おそらく、バッファは「常にフル*」である必要はありません。そこにはパケットが決して少なくないように、バッファを上に置いておかなければなりません。 – slim

+0

@slimはい、まさに私が伝えようとしていたことです。 – Durandal

+0

ありがとう、素敵な答え! – SalkinD

関連する問題