- Obtener vínculo
- X
- Correo electrónico
- Otras apps
Bienvenidos a mi nuevo post!!
En esta ocasión les quiero compartir un programa hecho en Java, su función es servir a los clientes que se conecten a él, y lo haremos con Sockets e Hilos en consola.
Les compartiré dos servidores diferentes, bueno en otras palabras, habrá dos escenarios:
1.- El servidor atenderá a múltiples clientes de manera concurrente, todos a la vez, en este caso el servidor estará enviando archivos a cada uno de los usuarios conectados al mismo tiempo, para que se vea la concurrencia es recomendable correrlo con archivos mayores de 50 Megabytes.
2.- El servidor atenderá a múltiples clientes de manera secuencial, es decir, todos se conectarán al mismo tiempo, pero primero atenderá a uno, en cuanto termine de atender (enviar el archivo) de inmediato comenzara a atender al siguiente, y así sucesivamente hasta terminar con todos los clientes.
Podemos enviar cualquier tipo de archivos(.exe, .jpeg, .iso, .jar, .pdf, .bat, .dll, etc).
La funcionalidad del cliente será la siguiente:
El cliente podrá funcionar en los dos tipos de servidores, así que será el mismo.
El cliente se conectará al servidor, y escribirá un archivo que quiera, de la siguiente manera; archivo.exe, archivo.iso, archivo.png, etc.
Y el Servidor buscará ese archivo en el directorio establecido, si lo encuentra mandará mensaje al cliente que si lo encontró y de inmediato iniciará la transferencia del archivo, de lo contrario enviará un mensaje que no lo encontró.
Bueno teniendo esto en cuenta, podemos pasar a ver el código.
Les compartiré dos servidores diferentes, bueno en otras palabras, habrá dos escenarios:
1.- El servidor atenderá a múltiples clientes de manera concurrente, todos a la vez, en este caso el servidor estará enviando archivos a cada uno de los usuarios conectados al mismo tiempo, para que se vea la concurrencia es recomendable correrlo con archivos mayores de 50 Megabytes.
2.- El servidor atenderá a múltiples clientes de manera secuencial, es decir, todos se conectarán al mismo tiempo, pero primero atenderá a uno, en cuanto termine de atender (enviar el archivo) de inmediato comenzara a atender al siguiente, y así sucesivamente hasta terminar con todos los clientes.
Podemos enviar cualquier tipo de archivos(.exe, .jpeg, .iso, .jar, .pdf, .bat, .dll, etc).
La funcionalidad del cliente será la siguiente:
El cliente podrá funcionar en los dos tipos de servidores, así que será el mismo.
El cliente se conectará al servidor, y escribirá un archivo que quiera, de la siguiente manera; archivo.exe, archivo.iso, archivo.png, etc.
Y el Servidor buscará ese archivo en el directorio establecido, si lo encuentra mandará mensaje al cliente que si lo encontró y de inmediato iniciará la transferencia del archivo, de lo contrario enviará un mensaje que no lo encontró.
Bueno teniendo esto en cuenta, podemos pasar a ver el código.
Código del Servidor Concurrente
package demoserverconcurrente; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.ServerSocket; import java.net.Socket; import javax.swing.JOptionPane; /** * * @author Ivan Luis Jimenez */ public class concurrente { /** * @param args the command line arguments */ public static void main(String[] args) throws IOException, InterruptedException { Socket s = null; ServerSocket ss = null; Tarea ob; int id = 0; try { ss = new ServerSocket(5432); while(true){ Tarea.escribir("Socket escuchando en puerto 5432"); s = ss.accept(); id++; JOptionPane.showMessageDialog(null, "Se conecto un nuevo cliente", "Cliente "+id, 2); Tarea.escribir("\nSe conecto el cliente No." + id + " desde la IP: " + s.getInetAddress()); Tarea.escribir("**************************************************"); ob = new Tarea(s, id); ob.start(); } } catch (IOException e) { Tarea.escribir(e.getMessage() + " [servidor]"); System.exit(3); } finally { } } static class Tarea extends Thread { int id; Socket s = null; /* *Atributos para manejar salida y entrada de texto */ ObjectInputStream ois = null; ObjectOutputStream oos = null; DataInputStream entradaCliente = null; DataOutputStream salidaCliente = null; /* *Atributos para manejar salida de archivos */ File archivo = null; long tiempoinicio = 0; long tiempofinal= 0; long tiempo_total=0; long initialTime; private Tarea(Socket socket, int id) { this.s = socket; this.id = id; } boolean checar(String nombre) { archivo = new File("C:\\Users\\Jony\\Desktop\\TOOL\\Trimestre I UAM\\Sistemas Distribuidos\\2. Servidores multiprocesos, concurrentes y multihilos\\Demoserverconcurrente\\origen\\" + nombre); if (archivo.exists()) { return true; } else { return false; } } public void run() { try { entradaCliente = new DataInputStream(s.getInputStream()); salidaCliente = new DataOutputStream(s.getOutputStream()); String nombreArchivo = entradaCliente.readUTF(); if (checar(nombreArchivo) == true) { tiempoinicio=(System.currentTimeMillis() - this.initialTime); System.out.println("El servidor comienza envio a cliente :" + id + " EN EL TIEMPO: " + (System.currentTimeMillis() - this.initialTime) + " milisegundos"); salidaCliente.writeBoolean(true); salidaCliente.writeUTF("SI existe el archivo:" + nombreArchivo + " en el servidor"); salidaCliente.writeUTF("Tamaño del archivo:" + (archivo.length() / 1024) + " KB | Nombre:" + archivo.getName()); salidaCliente.writeInt((int) archivo.length()); salidaCliente.writeUTF(nombreArchivo); escribir("Enviando archivo:" + nombreArchivo + " a " + s.getInetAddress()); FileInputStream entrada = new FileInputStream(archivo); BufferedInputStream leerArch = new BufferedInputStream(entrada); // Creamos el flujo de salida BufferedOutputStream salida = new BufferedOutputStream(s.getOutputStream()); // Creamos un array de tipo byte byte[] arreglo = new byte[(int) archivo.length()]; // Leemos el archivo y lo introducimos en el array de bytes leerArch.read(arreglo); // Realizamos el envio de los bytes que conforman el archivo for (int i = 0; i < arreglo.length; i++) { salida.write(arreglo[i]); } tiempofinal=(System.currentTimeMillis() - this.initialTime); tiempo_total=tiempofinal-tiempoinicio; escribir("Archivo Enviado a cliente:" + id); System.out.println("El servidor termino con cliente" + id + " EN UN TIEMPO DE: " + tiempo_total + " milisegundos"); System.out.println("Tiempo del cliente "+id +": ("+(System.currentTimeMillis() - this.initialTime)+") milisegundos"); salida.flush(); salida.flush(); salida.close(); entrada.close(); } if (checar(nombreArchivo) == false) { salidaCliente.writeBoolean(false); salidaCliente.writeUTF("NO existe el archivo:" + nombreArchivo + " en el servidor"); escribir("se envio respuesta al cliente"); } } catch (Exception ex) { escribir(ex.getMessage() + " id:" + id); } finally { try { if (oos != null) { oos.close(); } if (ois != null) { ois.close(); } if (s != null) { s.close(); } System.out.println("Termino proceso para cliente: " + id); } catch (Exception e) { System.out.println(e.getMessage() + " [servidor]"); } } } public static void escribir(String txt) { System.out.println(txt); } } }Ahora trataré de explicarles el código: El servidor consta de dos clases, una llamada concurrente y la otra se llama tarea. El la clase concurrente sólo levantaremos el servidor, y pondremos a la escucha de los clientes con un ciclo infinito. en el método main declaramos las variables: El socket para recibir al cliente cuando se conecte. Y el ServerSocket para levantar el servidor. Con Tarea, creamos un objeto de la otra clase para llamar al método run(); Y un id para llevar el contador de clientes conectados.
Socket s = null; ServerSocket ss= null; Tarea ob; int id = 0;Ahora dentro de un try catch metemos todo el código de la escucha del servidor. Con ss = new ServerSocket(5432); le indicamos en que puerto estará a la escucha, y en se puerto se conectará el cliente. Con el while(true) trabajamos con un ciclo infinito. Con Tarea.escribir("String"); mandamos a llamar el método de la otra clase y le mandamos una cadena para que la imprima en pantalla. Esto para trabajar con el mismo método en ambas clases y no declarar otro método, esto nos ahorrará memoria. Con s = ss.accept(); estamos a la escucha del cliente, digamos que es un pause del servidor, no sigue hasta que un cliente se conecte a él, en el momento que se conecten, pasa a la siguiente linea. Con id++; aumentamos el contador; Y nuevamente con Tarea.escribir("Striing"); mandamos una cadena para avisar que ya se conecto un cliente desde la ip que sea. Con ob = new Tarea(s, id); creamos una nueva instancia, objeto, proceso, hilo o como mas le entiendan, y le manda el id y el socket que se recibió. Con ob.start(); Lanzamos el hilo, ejecutamos el hilo para que procese la petición del cliente. Algún error se captura en el Catch.
try { ss = new ServerSocket(5432); while(true){ Tarea.escribir("Socket escuchando en puerto 5432"); s = ss.accept(); id++; Tarea.escribir("\nSe conecto el cliente No." + id + " desde la IP: " + s.getInetAddress()); Tarea.escribir("**************************************************"); ob = new Tarea(s, id); ob.start(); } } catch (IOException e) { Tarea.escribir(e.getMessage() + " [servidor]"); System.exit(3); } finally { }La otra clase Tarea hace todo el proceso,sólo recibe el id, y el socket. Se declara otro Socket dentro de esta clase, esto para pasarle el socket que se acaba de recibir. Declaramos objetos para mandar y recibir datos del servidor al clinte, y del cliente al servidor, tal como lo vemos en el constructor de la clase.
int id; Socket s = null; /* *Atributos para manejar salida y entrada de texto */ ObjectInputStream ois = null; ObjectOutputStream oos = null; DataInputStream entradaCliente = null; DataOutputStream salidaCliente = null; /* *Atributos para manejar salida de archivos */ File archivo = null; //atributos para manejar tiempos de los cliente long tiempoinicio = 0; long tiempofinal= 0; long tiempo_total=0; long initialTime; private Tarea(Socket socket, int id) { this.s = socket; this.id = id; }El siguiente método sólo checa si existe el archivo en el directorio asignado. Si existe devuelve un true, sino un false.
boolean checar(String nombre) { archivo = new File("C:\\Users\\Jony\\Desktop\\TOOL\\Trimestre I UAM\\Sistemas Distribuidos\\2. Servidores multiprocesos, concurrentes y multihilos\\Demoserverconcurrente\\origen\\" + nombre); if (archivo.exists()) { return true; } else { return false; } }Y ahora el método run(). Éste método es el objeto de estudio del servidor. Los comentario los escribiré dentro del código para que no me sea complicado la edición. ;-)
public void run() { try { entradaCliente = new DataInputStream(s.getInputStream());// Flujo de entrada para recibir mensajes o algo del cliente. salidaCliente = new DataOutputStream(s.getOutputStream());// Flujo de salida, esto para enviar mensajes o algo al cliente. String nombreArchivo = entradaCliente.readUTF();//Con esta linea, estamos leyendo un mensaje del cliente. if (checar(nombreArchivo) == true) { // Si existe el archivo realiza todo el proceso tiempoinicio=(System.currentTimeMillis() - this.initialTime);//inicia el contador del tiempo System.out.println("El servidor comienza envio a cliente :" + id + " EN EL TIEMPO: " + (System.currentTimeMillis() - this.initialTime) + " milisegundos");// Se imprime en pantalla que ya inicio el el envio al cliente salidaCliente.writeBoolean(true);// Se le envia true al cliente, esto para indicarle que si se encontró el archivo que busca. salidaCliente.writeUTF("SI existe el archivo:" + nombreArchivo + " en el servidor");// Se le manda otra confirmación pero como texto. salidaCliente.writeUTF("Tamaño del archivo:" + (archivo.length() / 1024) + " KB | Nombre:" + archivo.getName());// Se le envía el tamaño del archivo como mensaje(texto - String) salidaCliente.writeInt((int) archivo.length());// Se le envía el tamaño como entero salidaCliente.writeUTF(nombreArchivo);// Se le envía el nombre del archivo como cadena escribir("Enviando archivo:" + nombreArchivo + " a " + s.getInetAddress());//se escribe en servidor que se esta enviando el archivo FileInputStream entrada = new FileInputStream(archivo);// creamos flujo para almacenar en él el archivo que se va a enviar BufferedInputStream leerArch = new BufferedInputStream(entrada);//flujo para leer el archivo // Creamos el flujo de salida BufferedOutputStream salida = new BufferedOutputStream(s.getOutputStream()); // Creamos un array de tipo byte para almacenar el archivo en un arreglo byte[] arreglo = new byte[(int) archivo.length()]; // Leemos el archivo y lo introducimos en el array de bytes leerArch.read(arreglo); // Realizamos el envio de los bytes que conforman el archivo //con esto estamos enviando al cliente el archivo, byte por byte for (int i = 0; i < arreglo.length; i++) { salida.write(arreglo[i]);//escribiendo en cliente } tiempofinal=(System.currentTimeMillis() - this.initialTime); tiempo_total=tiempofinal-tiempoinicio;//capturamos tiempo de fin de envio escribir("Archivo Enviado a cliente:" + id); System.out.println("El servidor termino con cliente" + id + " EN UN TIEMPO DE: " + tiempo_total + " milisegundos");// se imprime el tiempo que tardo con el cliente en especifico System.out.println("Tiempo del cliente "+id +": ("+(System.currentTimeMillis() - this.initialTime)+") milisegundos");// Se imprime el tiempo que lleva hasta el momento, tomando en cuenta el primero hasta el último cliente salida.flush();//Se limpia la salida salida.flush();// otra vez por si las moscas ;-) salida.close();// se cierra el flujo entrada.close();//se cierra el flujo } if (checar(nombreArchivo) == false) {// si no se encuentra el archivo salidaCliente.writeBoolean(false);// se manda al cliente un false salidaCliente.writeUTF("NO existe el archivo:" + nombreArchivo + " en el servidor");//se envía al cliente un mensaje que no existe escribir("se envio respuesta al cliente");//al final se imprime que se envío respuesta al cliente, esto sólo para asegurarnos ;-) } } catch (Exception ex) { escribir(ex.getMessage() + " id:" + id);// cualquier error se captura aquí } finally { try { if (oos != null) { oos.close(); } if (ois != null) { ois.close(); } if (s != null) { s.close(); } System.out.println("Termino proceso para cliente: " + id); } catch (Exception e) { System.out.println(e.getMessage() + " [servidor]"); } }Y bueno esto fue el Servidor Con concurrente. El servidor secuencial es lo mismo que el concurrente, sólo que agregaremos una linea. ;-) el método .join(); espera a que termine el hilo que se esta procesando, y una vez que termino, continua con el siguiente.
while(true){ Tarea.escribir("Socket escuchando en puerto 5432"); s = ss.accept(); id++; Tarea.escribir("\nSe conecto el cliente No." + id + " desde la IP: " + s.getInetAddress()); Tarea.escribir("**************************************************"); ob = new Tarea(s, id); ob.start(); ob.join();//----> ésta linea y listo ya es secuencial }Ahora el Programa Cliente Será un poco mas breve para explicar el cliente.
package cliente; /** * * @author Ivanovich */ import java.awt.Desktop; import java.net.*; import java.io.*; public class Cliente { /* *atributos para manejar salida y entrada de texto */ BufferedReader delTeclado; DataOutputStream alservidor; FileInputStream entrada; /* *atributos para manejar entrada de archivos */ ObjectInputStream ois = null; ObjectOutputStream oos = null; FileOutputStream destino = null; BufferedOutputStream out = null; BufferedInputStream in = null; boolean respuesta = false; int tam = 0; String nombreArchivo = null; //Metodo iniciar el servidor cliente public void iniciar() { try { Socket yo = new Socket("127.0.0.1", 5432);// instanciamos al Socket, le mandamos la ip del servidor y el mismo puerto en el que esta escuchando el servidor. /* *Declaramos los flujos para enviar y recibir mensajes del servidor. */ delTeclado = new BufferedReader(new InputStreamReader(System.in)); alservidor = new DataOutputStream(yo.getOutputStream()); DataInputStream delServidor = new DataInputStream(yo.getInputStream()); escribir("Teclee el nombre del archivo:");//Le indicamos al cliente que debe escribir el nombre del archivo que desea. String el = delTeclado.readLine();//Se lee la linea escrita por el cliente y se guarda en la variable el. alservidor.writeUTF(el);// con esta linea le estamos enviando la cadena al servidor respuesta = delServidor.readBoolean();//y se recibe la respuesta del servidor if (respuesta == true) {// si la respuesta que se recibió del servidor es true, se prepara para recibir el archivo escribir("[Servidor]" + delServidor.readUTF());//Se recibe la cadena que indica que SI existe el archivo escribir("[Servidor]:" + delServidor.readUTF());// Se recibe la cadena que indica el tamaño del archivo tam = delServidor.readInt();//se recibe tamaño del archivo como entero nombreArchivo = delServidor.readUTF();//se recibe el nombre del archivo destino = new FileOutputStream("C:\\Users\\Jony\\Desktop\\TOOL\\Trimestre I UAM\\Sistemas Distribuidos\\2. Servidores multiprocesos, concurrentes y multihilos\\Envioarchivo\\Cliente_concurrente_secuencial\\destino\\" + nombreArchivo);// le asignamos la ruta en la cual se guardará el archivo recibido. out = new BufferedOutputStream(destino);//creamos flujos como en el servidor para recibir el archivo in = new BufferedInputStream(yo.getInputStream()); // Creamos el array de bytes para leer los datos del archivo byte[] buffer = new byte[tam]; // Obtenemos el archivo mediante la lectura de bytes enviados // leemos el archivo que se recibe for (int i = 0; i < buffer.length; i++) { buffer[i] = (byte) in.read(); } // Escribimos el archivo en la dirección corresondiente out.write(buffer); escribir("Se recivio el archivo"); //Limpiamos out.flush(); //Cerramos flujos //abrimos el archivo recivido abrir_archivo(); // } in.close(); out.close(); yo.close(); } else { escribir("[Servidor]" + delServidor.readUTF()); yo.close(); } } catch (Exception e) { System.out.println("error " + e.getMessage() + " cliente"); } } // en el método main sólo mandamos a llamar el método iniciar(); public static void main(String args[]) { Cliente ea = new Cliente(); ea.iniciar(); } // el metodo que imprime en pantalla public static void escribir(String txt) { System.out.println(txt); } // el método que abre el archivo que se recibió public void abrir_archivo() { try { //indicamos la ruta File objetofile = new File("C:\\Users\\Jony\\Desktop\\TOOL\\Trimestre I UAM\\Sistemas Distribuidos\\2. Servidores multiprocesos, concurrentes y multihilos\\Envioarchivo\\Cliente_concurrente_secuencial\\destino\\" + nombreArchivo); Desktop.getDesktop().open(objetofile);//abrimos el archivo } catch (IOException ex) { System.out.println(ex); } } }Si observaron todo esta sincronizado, es decir si uno envía en otro tiene que recibir, y viceversa.
Bueno esto sería el proyectito.
Las capturas se las dejo en un archivo de PDF junto con el código de los programas vale.
Link de descarga:
Descargar
http://raboninco.com/GDRv
Created By Ivan Luis Jimenez
Alguna duda, comentario o sugerencia, en la parte de abajo pueden escribirme.
Hilos en Java
Thread Java
Multihilos en Java
MultiThread Java
Cliente-Servidor en JAVA
Cliente-Servidor Sockets e Hilos en JAVA
Servidor concurrente y secuencial en JAVA
Servidor de Archivos con JAVA(Sockets e Hilos)
Sockets e Hilos en JAVA
- Obtener vínculo
- X
- Correo electrónico
- Otras apps
Comentarios
una Duda como puedo enviar la lista de archivos del servidor al cliente para que escoja el cliente el archivo que desea descargar, intente con un ObjectOutputStream pero tuve problemas
ResponderBorrarBuena pregunta, lo mas recomensable es hacer lectura de todos los archivos del directorio en donde este el repositorio de archivos que quieras compartir de la siguiente manera:
ResponderBorrarDeclaras un arreglo en el que guardarás todas las direcciones que encuentre
Vector direcciones = new Vector();
File dir = new File("c:\winnt");
String[] ficheros = dir.list();
if (ficheros == null)
System.out.println("No hay ficheros en el directorio especificado");
else {
for (int x=0;x<ficheros.length;x++)
direcciones.add(ficheros[x].toString());
}
y nadamas le envias el arreglo al cliente.
Puedes agregarle al cliente un botón que refresque las direcciones (nombres de los archivos).
Saludos!
Hola, que tal estoy ejecutando el programa desde mi Mac, pero me dice que no encuentra el archivo he guardado las rutas del servidor y cliente en el código de la siguiente manera
ResponderBorrarServidor: /Users/Fabian/Desktop/servidor
Cliente: /Users/Fabian/Desktop/cliente
En dónde es que te manda ese mensaje? a la hora de ejecutarlo? o de abrir el archivo enviado?
BorrarPrimero ejecuto el servidor y despues el cliente ambos en netbeans .. el cliente me.pide que ingrese el nombre del archivo y lo ingreso asi "foto.jpeg" y le doy enter y me dice que no se encontró el archivo en el destino.. y se acaba la ejecución
BorrarSi, entiendo. Lo que pasa es que la ruta que se especifica en el programa es otra a la que estas trabajando, por tanto, tu debes cambiar la ruta que se indica en el programa, tal ruta se encuentra el el servidor en el método que se llama checar(), ahí tu debes poner la ruta de tus archivos que quieres que el cliente quiera descargar
BorrarSi claro eso es lo que hice en un inicio la ruta del servidor es /Users/Fabian/Desktop/servidor donde servidor es una carpeta en el escritorio donde guardo los archivos. Pero el codigo de cliente me dice que los archivos no existen en el servidor
BorrarColoca la ruta absoluta de la carpeta, y coloca los archivos dentro de la carpeta. Debes escribisrla tal y como se llama el archivo, con su extensión, por ejemplo si es imagen.jpg, tienes que ponerle así al momento de buscar.
BorrarEso mismo he estado haciendo pero no funciona... las rutas absolutas son las que le puse en anteriores comentarios. :/ no se que puede ser.
ResponderBorrarIntenta colocar, C:\\Users\\Fabian\\Desktop\\ tiene que funcionar
ResponderBorrar