sirve - salida estandar en java
¿Cómo puedo almacenar en búfer mis flujos de entrada/salida/archivo Java correctamente? (2)
Estoy escribiendo una aplicación que necesita enviar un archivo a través de la red. Solo me han enseñado a usar las clases estándar java.net y java.io hasta ahora (en mi primer año de universidad), así que no tengo experiencia con java.nio y netty y todas esas cosas lindas. Tengo un servidor / cliente en funcionamiento configurado usando las clases Socket y ServerSocket junto con las secuencias BufferedInput / OutputStreams y BufferedFile, de la siguiente manera:
El servidor:
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!");
}
}
Y el cliente:
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!");
}
}
Al principio, no estaba usando el búfer, y escribía cada int desde in.read (). Eso me dio una transferencia de 200kb / s según mi gadget de monitor de red en Windows 7. Luego lo cambié como arriba pero usé buffers de 4096 byte y obtuve la misma velocidad, pero el archivo recibido era generalmente un par de kilobytes más grande que el archivo fuente, y ese es mi problema. Cambié el tamaño del búfer a 8192 y ahora obtengo una transferencia de 3.7-4.5mb / seg a través de la conexión inalámbrica a mi computadora portátil, que es lo suficientemente rápido por ahora, pero todavía tengo el problema de que el archivo se haga un poco más grande (lo que causaría fallar una prueba de hash md5 / sha) cuando se recibe.
Entonces mi pregunta es ¿cuál es la forma correcta de almacenar en búfer para obtener velocidades decentes y terminar exactamente con el mismo archivo en el otro lado? Hacer que vaya un poco más rápido también sería bueno, pero estoy contento con la velocidad por ahora. Supongo que un buffer más grande es mejor hasta cierto punto, solo necesito encontrar cuál es ese punto.
Si realmente quiere que sea ''tan perfecto'', debería echar un vistazo a la declaración try-catch-with-resources y al paquete java.nio (o cualquier biblioteca derivada de nio).
Está ignorando el tamaño de los datos realmente leídos.
while (in.read(b) != -1) {
fout.write(b);
}
siempre escribirá 8192 bytes incluso si solo se lee un byte. En cambio, sugiero usar
for(int len; ((len = in.read(b)) > 0;)
fout.write(b, 0, len);
Sus búferes son del mismo tamaño que su byte [], por lo que en realidad no están haciendo nada en este momento.
El MTU para la mayoría de las redes tiene alrededor de 1500 bytes y se obtiene una mejora del rendimiento en redes más lentas (hasta 1 GB) de hasta 2 KB. 8 KB tan bien también. Más grande que eso es poco probable que ayude.