29 junio, 2021

Enviar un archivo desde un cliente a un servidor en Java

Utilizando Sockets elabore una aplicación que permita enviar un archivo de texto desde un cliente a un servidor. En el lado del servidor utilice Thread.


El siguiente ejercicio viene por parte de un seguidor de la página. 



Antes de ver la solución, recordemos que es un socket y para qué sirve.

¿Qué es un socket?

Un Socket es una conexión entre dos host. Bajo esta conexión, se pueden ejecutar las siguientes operaciones básicas:

• Conectarse a una máquina remota.
• Enviar datos.
• Recibir datos.
• Cerrar una conexión.
• Escuchar datos entrantes.
• Aceptar conexiones de máquinas remotas.

La clase java Socket, la cual es usada tanto por aplicaciones cliente como aplicaciones servidor, tiene métodos que permiten implementar las cuatros primeras operaciones; las restantes, son exclusivas de aplicaciones servidor. Las aplicaciones servidor siempre esperan por aplicaciones cliente que se conecten a ellas y son implementadas por la clase ServerSocket.

Los programas java utilizan normalmente sockets cliente de la siguiente manera:

1. El programa crea un nuevo socket utilizando el constructor Socket().
2. El socket intenta conectarse a un host remoto.
3. Una vez establecida la conexión, las máquinas local y remota obtienen flujos de entrada y salida desde el socket y usan estos flujos para intercambiar información.
4. Cuando la transmisión de datos ha sido completada, una de las dos partes, o ambas, cierran la conexión. 

La clase ServerSocket contiene todo lo necesario para poder escribir un servidor en Java. Por ejemplo:

- Tiene constructores que crean objetos ServerSocket.
- Métodos que escuchan por conexiones en un puerto específico.
- Métodos que retornan un objeto Socket (cliente) cuando una conexión es realizada, de modo que se puedan enviar y recibir datos.

El ciclo de vida de un servidor básico es el siguiente:

1. Un nuevo ServerSocket es creado utilizando un puerto específico.
2. El ServerSocket escucha por intentos de conexión entrantes usando su método accept( ).
3 .accept( ) bloquea hasta que un cliente intenta hacer una conexión, en ese caso se retorna un objeto Socket conectándose el cliente y el servidor.
4. Dependiendo del tipo de servidor se invocan los métodos getInputStream y getOutputStream.
5. El servidor y el cliente interactúan de acuerdo a un protocolo preestablecido hasta que se debe cerrar la conexión.
6. El servidor, el cliente, o ambos cierran la conexión.
7. El servidor retorna al paso 2 y espera por la siguiente conexión.

¿Qué es un Thread?

Los Threads son hilos de ejecución que simulan ser ejecutados en paralelo dentro de un programa principal. Un thread comparte memoria y datos con el resto del programa Principal.

El uso de threads en java nos permite contar con un entorno de ejecución asíncrono, es decir, varias tareas pueden ser ejecutadas de manera simultánea. 

Muy bien, sabiendo estos conceptos, les dejo la solución al ejercicio que no envió Victor desde facebook.

Solución:

ServerFileHandler

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package problema01;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

// Crea un hilo de ejecución implementando la interfaz Runnable.
public class ServerFileHandler implements Runnable {

	// Atributos privados.
	private final String path = "c:/inbox"; // Ruta para guardar el archivo recibido.
	private ServerSocket ss; // Socket del servidor.
	private int port; // Puerto para la conexión.
	private boolean isOn; // Estado del servidor.
	private Thread serverThread; // Hilo de ejecución.

	// Constructor de la clase.
	public ServerFileHandler(int port, boolean isOn) {
		// Inicializa los atributos: puerto y estado del servidor.
		this.port = port;
		this.isOn = isOn;

		/**
		 * Dentro de un método de la clase, la referencia this contiene la dirección de
		 * memoria del objeto que invocó al método. La referencia this es un parámetro
		 * oculto añadido por el compilador. Una de sus aplicaciones más comunes es
		 * cuando el nombre de un parámetro coincide con el nombre de una variable
		 * miembro. En este caso, su objetivo es diferenciar la variable miembro del
		 * parámetro en sí.
		 **/

		try {
			// Crea el socket para el servidor en el puerto especificado.
			ss = new ServerSocket(port);
			// Crea un Thread; y con la referencia "this", el objeto de la
			// interface runnable es pasado como argumento al constructor.
			serverThread = new Thread(this);
			// Inicia el Thread (invoca al método run).
			serverThread.start();
			System.out.println("Servidor encendido..."); // Esperando por una conexión...
		} catch (IOException e) {
			// Falló alguna operación de E/S.
			e.printStackTrace();
		}
	}

	// Define un hilo de ejecución independiente.
	@Override
	public void run() {
		// Mientras el servidor está encendido.
		while (isOn) {
			try {
				// Comienza el socket y espera una conexión desde un cliente.
				Socket client = ss.accept();
				
				/************************************************/
				/** LEE LO QUE VENGA DEL CLIENTE (UN ARCHIVO). **/
				/************************************************/
				
				// Crea un flujo de entrada de datos.
				DataInputStream dis = new DataInputStream(client.getInputStream());
				// Obtiene el nombre del archivo.
				String fileName = dis.readUTF();
				System.out.println("El archivo recibido se llama: " + fileName);
				
				/*********************************************/
				/** GUARDA EL ARCHIVO RECIBIDO EN EL DISCO. **/
				/*********************************************/
				
				// Representa un directorio en el disco.
				File targetDirectory = new File(path);
				// Si el directorio no existe, se crea.
				if (!targetDirectory.exists()) {
					System.out.println("No existe, lo creamos.");
					targetDirectory.mkdir();
				}
				
				// Crea un flujo de salida de archivo.
				FileOutputStream fos = new FileOutputStream(path + File.separator + fileName);
				// Crea un arreglo de bytes de tamaño 1024 que contendrá los bytes del flujo de entrada.
				byte[] buffer = new byte[1024];
				// Crea una variable que almacena el byte leido.
				int byteRead;
				// Lee los bytes de datos del flujo de entrada contenido en la matriz.
				while ((byteRead = dis.read(buffer, 0, buffer.length)) != -1) {
					// Escribe los bytes en el archivo desde el byte 0 hasta el último byte leido.
					fos.write(buffer, 0, byteRead);
					// Si no hay ningún byte disponible (ha alcanzado el final de la secuencia), devuelve -1.
				}
				System.out.println("El archivo ha sido guardado en el servidor.");

				/*************************/
				/** LIBERA LOS RECURSOS **/
				/*************************/
				
				fos.close(); // Libera el recurso después de escribir en el archivo.
				dis.close(); // Libera el recurso despues de haber sido leido.
				client.close(); // Cierra el socket.
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	// Ejecuta la aplicación.
	public static void main(String[] args) {
		new ServerFileHandler(2509, true);
	}

}

ClientFileHandler

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package problema01;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;

public class ClientFileHandler {

	// Constructor de la clase.
	public ClientFileHandler(int port, String host, String filePath) {
		try {
			System.out.println("El cliente se prepara para enviar...");

			// Crea el socket para el cliente en el host y puerto especificado.
			Socket client = new Socket(host, port);
			
			/***********************************/
			/** ENVÍA EL ARCHIVO AL SERVIDOR. **/
			/***********************************/
			
			// Representa el archivo a enviar.
			File toCopy = new File(filePath);
			// Crea un flujo de entrada de archivo.
			FileInputStream fis = new FileInputStream(toCopy);
			// Crea un flujo de salida de datos.
			DataOutputStream dos = new DataOutputStream(client.getOutputStream());
			// Escribe el nombre del archivo en el flujo de salida.
			dos.writeUTF(toCopy.getName());
			
			// Crea un arreglo de bytes de tamaño 1024 que contendrá los bytes del archivo leido.
			byte[] buffer = new byte[1024];
			// Crea una variable que almacena el byte leido.
			int read;
			// Lee los bytes de datos del archivo leido contenido en la matriz.
			while ((read = fis.read(buffer, 0, buffer.length)) != -1) {
				// Escribe los bytes en el flujo de salida desde el byte 0 hasta el último byte leido.
				dos.write(buffer, 0, read);
			}
			System.out.println("El archivo fue enviado...");

			/*************************/
			/** LIBERA LOS RECURSOS **/
			/*************************/
			dos.close(); // Libera el recurso después de escribir en el flujo de salida.
			fis.close(); // Libera el recurso despues de haber sido leido.
			client.close(); // Cierra el socket.
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	// Ejecuta la aplicación.
	public static void main(String[] args) {
		new ClientFileHandler(2509, "localhost", "c:/poema.txt");
		new ClientFileHandler(2509, "localhost", "c:/prueba1.txt");
	}

}

DESARROLLO TUS ALGORITMOS 🔥🔥


✅ 1. Envía tu algoritmo.
✅ 2. Indica en qué lenguaje de Programación lo deseas.
✅ 3. Para qué fecha lo quieres.
✅ 4. De que país eres (para tu forma de pago)
✅ 5. También se desarrollan al momento.
✅ 6. Los 3 primeros ejercicios son gratis.
🔸 Explico cada ejercicio que desarrollo en el código.


No hay comentarios, ¡cuéntame algo!

Me gustaría saber tu opinión. ¡Saludos!