Autor Tema: Java ejemplo servidor ServerSocket cliente Socket TCP enviar ficheros File  (Leído 25032 veces)

Lorenzo31

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 381
    • Ver Perfil
[Nota: el código se encuentra en la respuesta de César Krall a continuación]

Buenas de nuevo, he estado realizando una práctica con TCP. Iré ampliandola pero dejaré aquí lo que llevo hasta el momento.

Basicamente es un servidor y una aplicacion cliente. Para abrirla debeis usar dos BlueJ, en uno abrir el Host, y en el otro acto seguido el cliente.

El programa buscará cualquier archivo (txt, en principio otra cosa no la he probado) y si lo encuentra lo enviará a la dirección destino, que en este caso es fija por el momento (cambiar la dirección que yo he puesto por la de vuestro escritorio o archivo destino).

Las premisas son las siguientes en este ejercicio:

Ejercicio 1:Cread un servidor que abra un fichero solicitado por un cliente y se lo envíe a través de la red. El servidor aceptará el siguiente formato de peticiones:


    Para proporcionar un fichero al cliente:

   1   get "nombre_completo_fichero"

    Para dar por finalizado el servicio:

   2   bye

Espero sirva a otras personas y bueno también acepto comentarios, sugerencias o cualquier consejo para aprender más del tema. Este es mi granito de arena en el foro, ir colgando código que vea interesante. (aviso en la primera busqueda tarda, sobre todo en copiar y madar el archivo seleccionado, por la creación del espacio imagino, luego es más fluido. Tened paciencia)

Saludos, espero comentarios y sugerencias de los expertos también.
« Última modificación: 24 de Junio 2018, 14:23 por Ogramar »

César Krall

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 2074
  • No vales por lo que dices, sino por lo que haces
    • Ver Perfil
    • aprenderaprogramar.com
Re:Java ejemplo servidor ServerSocket cliente Socket TCP enviar ficheros File
« Respuesta #1 en: 17 de Septiembre 2015, 09:54 »
Hola Lorenzo!

Se trata de una aportación valiosa porque se practica con muchos conceptos interesantes. Con tu permiso voy a trasladar el código que has creado para que esté visible dentro del hilo del foro y las personas que lo vean puedan hacerse una idea sobre el código sin tener que descargar el fichero como adjunto.

Clase FicheroServidor:

Código: [Seleccionar]
import java.io.*;
import java.net.*;
/**
 * Servidor envio archivos a usuarios
 *
 * @author Lorenzo31
 * @version (a version number or a date)
 */
public class FicheroServidor
{

    public static final int PORT = 4444;

    public static void main (String args[]) throws IOException {

        ServerSocket servidor = null;
        Socket cliente;
        BufferedReader entrada = null;
        //PrintWriter salida = null;
        OutputStream sendChannel = null;
        String cadena = ""; String comando = "";

        try{ servidor = new ServerSocket(PORT);
        }catch(IOException e){System.out.println("Error al conectar con el servidor"); System.exit(-1);}

        /* Se bloquea mientras escucha */
        System.out.println("Servidor escuchando: " + servidor + " " + servidor.getInetAddress());

        cliente = servidor.accept();
        while(!cliente.isClosed()){  //mientras sea distinto a close, sigue escuchando al usuario
            try{
                //Establece canal de entrada
                entrada = new BufferedReader (new InputStreamReader(cliente.getInputStream()));
                //Establece canal envio archivos
                sendChannel = cliente.getOutputStream();
                //lectura entrada usuario
                cadena = entrada.readLine();
            } catch(IOException e ) { System.out.println(e.getMessage()); }

            System.out.println("Buscando archivo solicitado en comando:" + cadena);
            //bucle for quita espacios a la cadena de entrada y lo guarda en comando
            for (int x = 0; x < cadena.length(); x++){
                if(!cadena.substring(x, x+1).equals(" ") && !cadena.substring(x, x+1).equals("\"")){ comando = comando + cadena.substring(x, x+1); }/*final for*/ }
            cadena = comando.substring(0, 3); //reasignamos a la cadena de entrada solo las 3 letras de la orden del usuario

            switch(cadena){  //coge los tres caracteres primeros y compara si es bye, get o otro que en ese caso no seria valido
                case "bye": System.out.println("Finalizada la conexion con el cliente."); cliente.close();  break;

                case "get":  //crea instancia de clase buscar archivo y invoca a la funcion buscador para encontrar el archivo solicitado
                BuscarArchivo find = new BuscarArchivo();
                File archivoEncontrado = find.buscador(comando.substring(3, comando.length() ), new File("C:\\"));
                if(archivoEncontrado != null){   //si es null no encontró el archivo sino sí que lo manda
                    new HiloEnvio (cliente, archivoEncontrado).start();  } else { sendChannel.write(-1); }
                cadena = ""; comando = "";
                break;
                default: sendChannel.write(-1); cadena = ""; comando = ""; //envio archivo vacio comando mal introducido
            }

        }

    }
}

Clase HiloEnvio:

Código: [Seleccionar]
import java.net.*;
import java.io.*;
/**
 * Write a description of class HiloEnvio here.
 *
 * @author (your name)
 * @version (a version number or a date)
 */
public class HiloEnvio extends Thread
{
    private File archivo;
    private Socket socketCliente = null;
    private FileInputStream fileChannel = null;
    private BufferedInputStream lectorArchivo = null;
    private OutputStream sendChannel = null;

    public HiloEnvio(Socket socketCliente, File archivo){ this.socketCliente = socketCliente; this.archivo = archivo; }

    public void run() {
        // envio de file
        try{
            byte [] mybytearray  = new byte [(int)archivo.length()];
            fileChannel = new FileInputStream(archivo);
            lectorArchivo = new BufferedInputStream(fileChannel);
            lectorArchivo.read(mybytearray,0,mybytearray.length);
            sendChannel = socketCliente.getOutputStream();
            System.out.println("Sending " + archivo + "(" + mybytearray.length + " bytes)");
            sendChannel.write(mybytearray,0,mybytearray.length);
            sendChannel.flush();
            System.out.println("Done.");
        }catch (IOException | NullPointerException e) { System.out.println("Interrumpido. ");
            interrupt();}       
    }
}

Clase BuscarArchivo

Código: [Seleccionar]
import java.io.*;
import java.net.*;
/**
 * Write a description of class BuscarArchivo here.
 *
 * @author (your name)
 * @version (a version number or a date)
 */
public class BuscarArchivo
{
   File archivoEncontrado = null; //si retorna null es que no lo ha encontrado
   
   public BuscarArchivo() { }
   
   public File buscador(String nombre, File raiz){
       
       File[] lista = raiz.listFiles();
       
       if(lista != null) {
           for(File elemento : lista) {
               if (elemento.isDirectory())  { //si es directorio vuelve a llamarse a si misma
                   buscador(nombre, elemento);
                } else if (nombre.equalsIgnoreCase(elemento.getName()))  //sino, si es igual encontrado
                  { archivoEncontrado = elemento; System.out.println("Archivo encontrado.");}
                }
            }
             return archivoEncontrado;
        } //cierre buscador
}

Clase FicheroCliente

Código: [Seleccionar]
import java.io.*;
import java.net.*;
/**
 * Write a description of class FicheroCliente here.
 *
 * @author (your name)
 * @version (a version number or a date)
 */
public class FicheroCliente
{
    public static void main(String[] args) throws IOException {

        int bytesRead;
        OutputStream fos = null;
        BufferedOutputStream bos = null;
        Socket socketCliente = null;

        PrintWriter salida = null;

        String hostName = InetAddress.getLocalHost().getHostName();
        /* Creamos un socket en el lado cliente, enlazado con un servidor que está en la misma máquina
        que el cliente y que escucha en el puerto 4444 */

        try{ socketCliente = new Socket(hostName, 4444);
            System.out.println("servidor conectado:" + hostName);

            //Obtenemos el canal de salida
            salida = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socketCliente.getOutputStream())),true);
        }catch(IOException e){
            System.err.println("No puede establecer conexion");
            System.exit(-1); }

        BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));

        String linea = "";

        /*El programa cliente no analiza los mensajes enviados por el usuario, simplemente los
         * reenvia al servidor hasta que este se despide con Adios*/
        while(!linea.equalsIgnoreCase("bye")){   

            do{
                System.out.println("Intrude comando válido:");
                //Leo la entrada del usuario
                linea = stdIn.readLine();
            }while (!linea.matches("[a-z][a-z][a-z] \".*\"") && !linea.equalsIgnoreCase("bye"));
            //La envia al servidor
            salida.println(linea);

            try {
                //reciibr archivo
                //Creamos array de bytes
                byte [] mybytearray  = new byte [66666];
                //Creamos objeto InputStream que abre la cadena de entrada para lectura del fichero que mande servidor
                InputStream cadenaReceptor = socketCliente.getInputStream();
                fos = new FileOutputStream("C:/Documents and Settings/Admin/Desktop/llegada.txt");
                bos = new BufferedOutputStream(fos);  //lee donde va a escribir

                bytesRead = cadenaReceptor.read(mybytearray,0,mybytearray.length);


                if(bytesRead == 1){   //1 valor que toma como mínimo un archivo Outputstream, significa archivo no encontrado o no buscado
                    System.out.println("Archivo no encontrado o comando erroneo");
                } else if(bytesRead == -1){ System.out.println("Sesion finalizada"); } //-1 valor que toma al no recibir ningun archivo erroneo ni correcto, solo con BYE

                else { bos.write(mybytearray, 0 , bytesRead);  //buffer escribe en el archivo asignado
                    bos.flush();
                    System.out.println("File " + "C:/Documents and Settings/Admin/Desktop/llegada.txt"
                        + " downloaded (" + bytesRead + " bytes read)");  }

            }catch(IOException e){ System.out.println("Error en la transmisión.");
                if (fos != null) fos.close();
                if (bos != null) bos.close();
                if (socketCliente != null) socketCliente.close(); }
        }

        if (fos != null) fos.close();
        if (bos != null) bos.close();
        if (socketCliente != null) socketCliente.close();

    }
}
Responsable de departamento de producción aprenderaprogramar.com

César Krall

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 2074
  • No vales por lo que dices, sino por lo que haces
    • Ver Perfil
    • aprenderaprogramar.com
Re:Java ejemplo servidor ServerSocket cliente Socket TCP enviar ficheros File
« Respuesta #2 en: 17 de Septiembre 2015, 10:01 »
Para orientar a quienes quieran probar el programa:

- En la clase FicheroCliente reemplazar C:/Documents and Settings/Admin/Desktop/llegada.txt por una ruta propia del pc donde estemos trabajando, por ejemplo C:/Users/Krall/Desktop/pruebas/llegada.txt

En esa ruta será donde se coloque el fichero enviado por el servidor (el fichero que vamos a descargar en el cliente)

Para hacer una prueba, crear un fichero por ejemplo denominado prueba.txt y ubicarlo en el escritorio (o en otro lugar).

Para comenzar, ejecutar el método main de la clase FicheroServidor. Es posible que salte una alerta de Firewall de Windows. En este caso elegir "Permitir acceso"

Por pantalla nos saldrá <<Servidor escuchando: ServerSocket[addr=0.0.0.0/0.0.0.0,localport=4444] 0.0.0.0/0.0.0.0
>>

Abrir otro entorno de ejecución Java y ejecutar el método main de la clase FicheroCliente

Por pantalla nos saldrá:

servidor conectado:NombreServer
Introduce comando válido:


Escribimos get "prueba.txt"

Con esto lo que hemos dicho es "busca el archivo prueba.txt dentro del servidor y descárgalo al cliente en la ruta C:/Users/Krall/Desktop/pruebas/llegada.txt" (o aquella ruta que hayamos indicado).

En la ventana de EnvioFicheros obtendremos al cabo de un par de minutos:

servidor conectado:Krall
Intrude comando válido:
get "prueba.txt"
File C:/Users/Krall/Desktop/pruebas/llegada.txt downloaded (66 bytes read)
Introduce comando válido:


Aquí como comando introduciremos bye para desconectar.

En la ventana EnvioFicheros obtendremos algo como esto

Servidor escuchando: ServerSocket[addr=0.0.0.0/0.0.0.0,localport=4444] 0.0.0.0/0.0.0.0
Buscando archivo solicitado en comando:get "prueba.txt"
Archivo encontrado.
Sending C:\Users\Krall\Desktop\prueba.txt(66 bytes)
Done.


Finalmente, como comprobación de que el archivo ha sido bajado desde el cliente al servidor iremos a la ruta donde indicamos que debía guardarse el archivo en el cliente del tipo C:/Users/Krall/Desktop/pruebas/llegada.txt y comprobaremos que el archivo se encuentra ahora en esa ruta

Una vez escribimos bye nos indicará que la sesión ha finalizado:

En la clase FicheroServidor

servidor conectado:Krall
Intrude comando válido:
get "prueba.txt"
File C:/Users/Krall/Desktop/pruebas/llegada.txt downloaded (66 bytes read)
Intrude comando válido:
bye
Sesion finalizada



En la clase EnvioFicheros:

Servidor escuchando: ServerSocket[addr=0.0.0.0/0.0.0.0,localport=4444] 0.0.0.0/0.0.0.0
Buscando archivo solicitado en comando:get "probandoLorenzo.txt"
Archivo encontrado.
Sending C:\Users\Krall\Desktop\prueba.txt(66 bytes)
Done.
Buscando archivo solicitado en comando:bye
Finalizada la conexion con el cliente.


Con esto hemos completado la ejecución del programa donde: hemos abierto una ejecución en el servidor, hemos abierto otra ejecución en el cliente, luego hemos pedido desde el cliente que busque un archivo en el servidor y lo descargue. Si lo encuentra tendremos el fichero en la ruta que hayamos indicado. Si no lo encuentra, o si hay algún problema, nos saldrá un mensaje de error.

Saludos!

Responsable de departamento de producción aprenderaprogramar.com

César Krall

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 2074
  • No vales por lo que dices, sino por lo que haces
    • Ver Perfil
    • aprenderaprogramar.com
Re:Java ejemplo servidor ServerSocket cliente Socket TCP enviar ficheros File
« Respuesta #3 en: 17 de Septiembre 2015, 10:03 »
No he revisado el código por ello voy solo a comentar algunas cosas, creo que sería bueno oir tu opinión o corrección.

- El cliente pide al servidor que le envíe un fichero que se encuentra en el servidor por ejemplo prueba.txt y que lo deposite en una ubicación del cliente por ejemplo C:/Users/Krall/Desktop/pruebas/llegada.txt

- En el servidor la búsqueda del fichero se hace mediante una búsqueda recursiva en todo el sistema de archivos. Sugerencia: esta búsqueda es muy costosa. ¿Por qué no defines una ubicación donde deba realizarse la búsqueda? (Por ejemplo dentro de una carpeta). De esa manera no tardaría tanto tiempo en realizar la búsqueda (tal y como está ahora puede requerir varios minutos)

- En el diseño los nombres de las clases no acaban de tener una representación clara de lo que son o lo que hacen. Por ejemplo no veo una clase Cliente ni una clase Servidor. Sería bueno oir una descripción del cometido de cada clase (que tendría que hacer quien ha creado el programa)  y quizás también un rediseño para dar mejores nombres a las clases. Por ejemplo BuscarArchivo no es un nombre coherente para una clase. Podría serlo BuscadorDeArchivos o algo similar, pero no es común que el nombre de una clase sea el infinitivo de un verbo. Hay nombres que no veo claros por ejemplo la clase FicheroServidor ¿representa un fichero servidor? Por ejemplo no veo claro que un fichero pueda recibir órdenes por consola, eso no se ve coherente.

Ante todo gracias por la aportación!

Responsable de departamento de producción aprenderaprogramar.com

Lorenzo31

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 381
    • Ver Perfil
Re:Java ejemplo servidor ServerSocket cliente Socket TCP enviar ficheros File
« Respuesta #4 en: 17 de Septiembre 2015, 16:02 »
Muy buenas César, ante todo gracias por las molestias de echarle un vistazo al proyecto.

Sobre el funcionamiento, es correcto todo lo que explicas, yo añadiría que para verificar si el comando introducido cumple los parametros solicitados he utilizado una funcion de la clase String muy interesante, que es matches().

Código: [Seleccionar]
while (!linea.matches("[a-z][a-z][a-z] \".*\"")
En este caso con unos parametros definidos de 3 letras de la a -z, seguido de una " inicial y una final (\") y con cualquier texto en medio de estas (.*) .

Sobre tu pregunta del nombre de las clases, bueno tienes toda la razón, no son nombres apropiados, el motivo es que en el mismo proyecto tengo 3 clases servidor más y tres clientes, de ahí ese nombre.

Para el proyecto final, lo documentaré mucho mejor y pondré nombres más clarificadores. El proyecto final tiene que aceptar multiples clientes (ya lo hago en uno anterior) y además añadir más funciones como modificar archivos etc...

Te adjuto el documento del que saqué los ejercicios y una breve parte teórica (insuficiente para lo que pide hacer luego). Pero si sirve para que otros practiquen el TCP genial. Es de la universidad Carlos III de madrid, una url.

http://www.it.uc3m.es/~celeste/docencia/cr/2003/PracticaSocketsTCP/

Cuando termine este ultimo proyecto colgaré todos los anteriores además de este.

Ah, y sobre la busqueda desde C: , sí esta claro que hace que tarde más, si no encuentra rápido el archivo, se podría pasar la carpeta en la que buscarlo, pero el ejercicio pedia expresamente que fuera busqueda en cualquier lugar y de ahí la forma de busqueda.

Cualquier otro comentario, encantado de leerte, me costó bastante entender la cantidad de cosas que hay que abrir, InputStream, Outputstream, BufferedInputStream, File además de array de bytes ... otras clases que aun no he probado son FileInputStream y FileOutputStream, si puedes explicarme brevemente la diferencia con las anteriores, te lo agradecería. Puede ser que permta el envio de archivos mayores o algo mas optimizado? aunque el tamaño va en funcion de los bytes declarados no del Input o Output.
Gracias César.

*Modifico para añadir, que pueden buscarse tantos archivos al a vez como se quiera, es decir get "test.txt", luego get "aprenderaprogramar.txt" etc.. y a partir de la segunda busqueda va muchisimo mas rápido.
Y una pregunta que me lleva un poco de cabeza, he probado a buscar y guardar una JPG, bien el servidor la encuentra y "dice que envia" 800.000 bytes (correcto) pero al recibirlo en el cliente, el InputStream.read() siempre coge un máximo de 65536 bytes.

No se porque, si le marco el length total, creo que tiene que ver con el OutputStream.write() que no llega a mandar el total, podrías añadirme alguna luz sobre este asunto, busco por las redes pero no encuentro respuesta. Gracias.
« Última modificación: 17 de Septiembre 2015, 18:02 por Lorenzo31 »

Lola Roches

  • Sin experiencia
  • *
  • Mensajes: 33
    • Ver Perfil
Re:Java ejemplo servidor ServerSocket cliente Socket TCP enviar ficheros File
« Respuesta #5 en: 19 de Septiembre 2015, 11:44 »
Hola chicos! Al probar el codigo me funciona bien pero tengo un problema resulta que despues de crearme el archivo en la ubicacion indicada de destino tiene el texto que había dentro pero unos instantes despues el archivo pasa a tener 0 bytes y el texto que tenia desaparece, es como si se sobreescribiera ¿que puede estar pasando?

Lorenzo31

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 381
    • Ver Perfil
Re:Java ejemplo servidor ServerSocket cliente Socket TCP enviar ficheros File
« Respuesta #6 en: 20 de Septiembre 2015, 01:46 »
Efectivamente en esta versión al lanzar el bye, no pasa por el while principal y ejecuta una transferencia de datos equivalente a 0.

Lo he corregido y adjunto el zip nuevo, pido a los moderadores sustituyan este por el que sale arriba de la página, disculpas toqué varias opciones no me di cuenta del fallo, gajes del oficio.

Gracias por darte cuenta Lola!
« Última modificación: 20 de Septiembre 2015, 11:17 por Alex Rodríguez »

Alex Rodríguez

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 2052
    • Ver Perfil
Re:Java ejemplo servidor ServerSocket cliente Socket TCP enviar ficheros File
« Respuesta #7 en: 20 de Septiembre 2015, 11:18 »
He trasladado el zip nuevo al mensaje inicial del hilo dejando de momento un solo zip (creo que así evitamos confusiones). Saludos.

Ogramar

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 2635
    • Ver Perfil
Re:Java ejemplo servidor ServerSocket cliente Socket TCP enviar ficheros File
« Respuesta #8 en: 22 de Septiembre 2015, 09:46 »
Hola he creado un hilo comentando las diferencias entre InputStream y BufferedInputStream localiza en https://www.aprenderaprogramar.com/foros/index.php?topic=3240.0

Salu2

Lorenzo31

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 381
    • Ver Perfil
Re:Java ejemplo servidor ServerSocket cliente Socket TCP enviar ficheros File
« Respuesta #9 en: 22 de Septiembre 2015, 09:56 »
Genial! gracias Ogramar, en un rato me la leo detenidamente, muy utiles los hilos de teoría, para aclarar conceptos.

Thanks !

davtor01

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 1
    • Ver Perfil
Como puedo descargar los codigos, para revisarlos

Ogramar

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 2635
    • Ver Perfil
Buenas, en la respuesta de César Krall tienes los códigos. Pulsa en seleccionar y copia el código de cada clase. Salu2

 

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".