29 junio, 2021

Enviar un objeto desde un cliente a un servidor en Java

Utilizando Sockets elabore una aplicación que permita enviar un objeto serializado 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. 


¿Qué es la serialización de objetos?

La serialización de objetos permite que un objeto sea transformado en una secuencia de bytes que posteriormente pueda ser recreada (deserializada) en el objeto original. Después de una deserialización,
el objeto tiene el mismo estado que poseía en el momento de ser serializado. 

Java proporciona esta facilidad a través de las interfaces ObjectInput y ObjectOutput. Estas interfaces permiten leer y escribir objetos desde y hacia flujos de entrada y salida respectivamente.

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

Solución:

Bean

 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
package problema02;

import java.io.Serializable;

// Clase serializada-
public class SanguchitoBean implements Serializable {

	private static final long serialVersionUID = 1L;

	// Atributos privados.
	private int id;
	private String nombre;
	private String descripcion;
	private boolean conPapas;

	// Métodos de acceso get/set.
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getNombre() {
		return nombre;
	}

	public void setNombre(String nombre) {
		this.nombre = nombre;
	}

	public String getDescripcion() {
		return descripcion;
	}

	public void setDescripcion(String descripcion) {
		this.descripcion = descripcion;
	}

	public boolean isConPapas() {
		return conPapas;
	}

	public void setConPapas(boolean conPapas) {
		this.conPapas = conPapas;
	}

}

ServerSerializableHandler

  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
package problema02;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

// Crea un hilo de ejecución implementando la interfaz Runnable.
public class ServerSerializableHandler 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 ServerSerializableHandler(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) {
			// No existe un servidor en este puerto.
			e.printStackTrace();
		}
	}

	// Define un hijo 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 OBJETO). **/
				/***********************************************/
				
				// Crea un flujo de entrada de objeto.
				ObjectInputStream ois = new ObjectInputStream(client.getInputStream());
				// Lee el objeto recibido.
				SanguchitoBean obj = (SanguchitoBean) ois.readObject();
				System.out.println("Se recibió el objeto: " + obj);
				
				/*********************************************/
				/** GUARDA EL OBJETO RECIBIDO EN EL DISCO. **/
				/*********************************************/
				
				// Crea un flujo de salida de objeto.
				ObjectOutputStream oos = new ObjectOutputStream(
						new FileOutputStream(path + File.separator + "objeto.txt"));
				// Escribe el objeto en el archivo creado.
				oos.writeObject(obj);
				System.out.println("El objeto ha sido guardado en el servidor.");
				
				/*************************/
				/** LIBERA LOS RECURSOS **/
				/*************************/
				
				oos.close(); // Libera el recurso después de escribir el objeto.
				ois.close();  // Libera el recurso despues de haber sido leido.
			} catch (IOException e) {
				// Si se produce una excepción de E/S de algún tipo.
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				// Cuando se intenta cargar una clase que no se encuentra.
				e.printStackTrace();
			}
		}

	}

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

}

ClientSerializableHandler

 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
package problema02;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class ClientSerializableHandler {

	// Constructor de la clase.
	public ClientSerializableHandler(int port, String host, SanguchitoBean obj) {
		try {
			System.out.println("El cliente se prepara para enviar un objeto...");
			
			// Crea el socket para el cliente en el host y puerto especificado.
			Socket client = new Socket(host, port);
			
			/***********************************/
			/** ENVÍA EL OBJETO AL SERVIDOR. **/
			/***********************************/
			
			// Crea un flujo de salida de objeto.
			ObjectOutputStream oos = new ObjectOutputStream(client.getOutputStream());
			// Escribe el objeto en el flujo de salida especificado.
			oos.writeObject(obj);
			System.out.println("El objeto fue enviado...");
			
			/*************************/
			/** LIBERA LOS RECURSOS **/
			/*************************/
			
			oos.close(); // Libera el recurso después de escribir el objeto.
			client.close(); // Cierra el socket.
		} catch (UnknownHostException e) {
			// No se pudo determinar la dirección IP del host.
			e.printStackTrace();
		} catch (IOException e) {
			// Se produjo una excepción de E/S de algún tipo.
			e.printStackTrace();
		}
	}

	// Ejecuta la aplicación.
	public static void main(String[] args) {
		// Crea un objeto de tipo setNombre serializado.
		SanguchitoBean obj = new SanguchitoBean();
		obj.setNombre("Sandwich de panza de rata");
		obj.setDescripcion("Delicioso sandwich con tripas de muca");
		obj.setId(1);
		obj.setConPapas(true);
		// Invoca al constructor de la clase pasándole como parámetros:
		// el puerto, el host y el objeto creado.
		new ClientSerializableHandler(2008, "localhost", obj);
	}

}


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!