2012-09-03 15 views
5

Sto scrivendo un'applicazione che deve inviare un file attraverso la rete. Mi è stato insegnato solo come utilizzare le classi standard java.net e java.io finora (nel mio primo anno di college) quindi non ho esperienza con java.nio e netty e tutte quelle belle cose. Ho un server/client di lavoro configurato con le classi Socket e ServerSocket con BufferedInput/OutputStreams e BufferedFile corsi d'acqua, come segue:Come posso bufferizzare correttamente i flussi di input/output/file Java?

Il server:

public class FiletestServer { 

    static ServerSocket server; 
    static BufferedInputStream in; 
    static BufferedOutputStream out; 

    public static void main(String[] args) throws Exception { 
    server = new ServerSocket(12354); 
    System.out.println("Waiting for client..."); 
    Socket s = server.accept(); 
    in = new BufferedInputStream(s.getInputStream(), 8192); 
    out = new BufferedOutputStream(s.getOutputStream(), 8192); 
    File f = new File("test.avi"); 
    BufferedInputStream fin = new BufferedInputStream(new FileInputStream(f), 8192); 

    System.out.println("Sending to client..."); 
    byte[] b = new byte[8192]; 
    while (fin.read(b) != -1) { 
     out.write(b); 
    } 
    fin.close(); 
    out.close(); 
    in.close(); 
    s.close(); 
    server.close(); 
    System.out.println("done!"); 
    } 
} 

E il client:

public class FiletestClient { 

    public static void main(String[] args) throws Exception { 
    System.out.println("Connecting to server..."); 
    Socket s; 
    if (args.length < 1) { 
     s = new Socket("", 12354); 
    } else { 
     s = new Socket(args[0], 12354); 
    } 
    System.out.println("Connected."); 
    BufferedInputStream in = new BufferedInputStream(s.getInputStream(), 8192); 
    BufferedOutputStream out = new BufferedOutputStream(s.getOutputStream(), 8192); 
    File f = new File("test.avi"); 
    System.out.println("Receiving..."); 
    FileOutputStream fout = new FileOutputStream(f); 
    byte[] b = new byte[8192]; 
    while (in.read(b) != -1) { 
     fout.write(b); 
    } 
    fout.close(); 
    in.close(); 
    out.close(); 
    s.close(); 
    System.out.println("Done!"); 
    } 
} 

Inizialmente non utilizzavo il buffering e scrivevo ogni int da in.read(). Questo mi ha portato a circa 200kb/s di trasferimento in base al mio gadget monitor di rete su Windows 7. Poi ho cambiato come sopra ma ho usato buffer 4096 byte e ottenuto la stessa velocità, ma il file ricevuto era solitamente un paio di kilobyte più grande del file sorgente, e questo è il mio problema. Ho cambiato la dimensione del buffer in 8192 e ora ottengo il trasferimento da 3.7-4.5mb/sec via wireless al mio portatile, che per ora è abbastanza veloce, ma ho ancora il problema che il file diventa leggermente più grande (il che potrebbe causarlo fallire un test hash md5/sha) quando viene ricevuto.

Quindi la mia domanda è qual è il modo corretto di buffering per ottenere velocità decenti e finire esattamente con lo stesso file sull'altro lato? Farlo andare un po 'più veloce sarebbe bello, ma per ora sono contento della velocità. Suppongo che un buffer più grande sia migliore fino a un certo punto, ho solo bisogno di trovare di che cosa si tratti.

risposta

5

Si sta ignorando la dimensione dei dati effettivamente letti.

while (in.read(b) != -1) { 
    fout.write(b); 
} 

scrive sempre 8192 byte anche se viene letto solo un byte. Invece io suggerisco di usare

for(int len; ((len = in.read(b)) > 0;) 
    fout.write(b, 0, len); 

vostri tamponi sono le stesse dimensioni come byte [] in modo che non stanno realmente facendo nulla per il momento.

L'MTU per la maggior parte delle reti è di circa 1500 byte e si ottiene un miglioramento delle prestazioni su reti più lente (fino a 1 GB) fino a 2 KB. 8 KB altrettanto bene. Più grande di quello è improbabile che aiuti.

+0

Ah, bastonatemi. – martijno

+0

@martijno Un segno che devo rallentare. ;) –

+0

Capisco ignorando la parte delle dimensioni dei dati che causa il problema ma non lo capisco per il ciclo. Sembra di leggere in avanti in un modo e scrive solo i dati dal buffer fino al punto in cui termina il contenuto effettivo: è corretto? EDIT: hai uno o più parentesi quadre, "((len = ..." dovrebbe essere "(len = ..." – Logan

Problemi correlati