Está en la página 1de 14

Práctica

Comunicaciones mediante el
protocolo UDP

Redes y Sistemas Distribuidos


para el Control
(ReSiDiCo)
DISCA-UPV ReSiDiCo

Contenido

1. Soporte en java a las comunicaciones mediante el protocolo UDP ..................... 3


2. Realización de dos aplicaciones, cliente y servidor, basadas en UDP .................. 3
2.1 Estructura del proyecto...................................................................................................................... 3
2.1.1 El paquete servidor (server) ................................................................................................................ 4
2.1.2 El paquete cliente (client)..................................................................................................................... 4
2.2 Realización de las aplicaciones........................................................................................................ 4
2.3 Realización de variantes de la práctica: servidor de hora ................................................... 5
2.4 Realización de variantes de la práctica: envío de objetos serializados .......................... 6
3. Incorporando una interfaz gráfica a nuestras aplicaciones ................................. 8
3.1 Instalación de WindowsBuilder ...................................................................................................... 8
3.2 Uso de WindowsBuilder..................................................................................................................... 9
3.2.1 Realización de los manejadores de eventos .............................................................................. 11
4. Realización de una aplicación cliente-servidor basada en UDP con interfaz
gráfica .................................................................................................................... 12

Pág: 2
DISCA-UPV ReSiDiCo

1. Soporte en java a las comunicaciones mediante el


protocolo UDP
La programación de comunicaciones con UDP en java se basa en las clases
DatagramSocket y DatagramPacket que permiten crear un socket UDP y,
posteriormente, enviar y recibir datagramas UDP sobre él.

Para poder recibir a través de un socket UDP es necesario que el socket escuche en
un puerto. Para ello, se crea un socket UDP mediante la orden:

DatagramSocket ds = new DatagramSocket(12345);

Con esto cualquier datagrama que llegue al puerto 12345 puede ser recibido
mediante la orden ds.receive(p); siendo p un objeto de la clase
DatagramPacket.

Dentro de cada datagrama encontramos un campo de datos que podemos obtener


mediante el método p.getData() que devuelve un vector de bytes con los datos
recibidos. También se dispone de los métodos p.getAddress() y
p.getPort() que devuelven la dirección y puerto respectivamente del origen
del mensaje recibido.

2. Realización de dos aplicaciones, cliente y servidor, basadas


en UDP
En esta primera parte de la práctica se va a desarrollar un proyecto con dos
aplicaciones básicas, cliente y servidor, basadas en UDP. El objetivo es obtener un
ejemplo con la estructura básica que implementa el protocolo de comunicaciones
UDP para comunicar diferentes aplicaciones utilizando las clases proporcionadas
en java. Posteriormente, basándonos en dicho ejemplo, se desarrollarán los demás
apartados de la práctica.

El proyecto a desarrollar consistirá en un servidor de eco, es decir, el servidor


responderá al cliente con el mismo mensaje que éste le haya enviado.

2.1 Estructura del proyecto

El proyecto se estructura en dos paquetes: el cliente y el servidor, los cuales se


describen a continuación.

Pág: 3
DISCA-UPV ReSiDiCo

2.1.1 El paquete servidor (server)

Consta del siguiente fichero:

• ServerUDP.java: es el esqueleto de una aplicación servidor secuencial que


realiza las siguientes operaciones:
o Espera la recepción de un mensaje a través de un socket.
o Envía su eco, es decir, el mismo mensaje recibido, como respuesta. Para
ello antes obtiene la dirección y puerto origen del mensaje recibido.
Observar que cuando se crea el DatagramSocket se especifica un número de
puerto donde recibir los mensajes, es decir, el puerto al que los clientes deberán
dirigir sus mensajes.

Visite este código y observe que existen EJERCICIOS.

2.1.2 El paquete cliente (client)

Consta de los siguientes ficheros:

• ClientUDP.java: implementa una clase que proporciona los métodos para


enviar y recibir mensajes a través de un socket UDP. Observar que en el
constructor se especifica a qué dirección (host) y port se van a enviar los
mensajes. Observar también que cuando se crea el DatagramSocket no se
especifica ningún puerto, sino que se deja a elección del sistema.

Visite este código y observe que existen EJERCICIOS.

• Client.java: es la aplicación cliente propiamente dicha. Utiliza un objeto de la


clase ClientUDP para realizar el siguiente bucle:

o Lee de teclado el mensaje a enviar.


o Envía el mensaje a la dirección y puerto del servidor.
o Espera la respuesta del servidor.
o Imprime el resultado por pantalla.

Visite este código y observe que existen EJERCICIOS.

2.2 Realización de las aplicaciones

Para la realización de las aplicaciones cree un proyecto Cliente-Servidor-


UDP y siga la metodología descrita en la práctica anterior para el desarrollo de una
aplicación Java.

Pág: 4
DISCA-UPV ReSiDiCo

1. Descargue los ficheros de ayuda al directorio de descargas.

2. Cree un proyecto Cliente-Servidor-UDP en el workspace según se


indicaba en la práctica anterior y cree también los paquetes en los que se
estructura: client y server.

3. Desarrolle el paquete server:


o Copie el fichero ServerUDP.java del directorio de descargas al
workspace.
o Realice los ejercicios propuestos.
o Ejecute y depure ServerUDP.java utilizando el menú Run... y
proporcionado los parámetros de ejecución que sean necesarios.

4. Desarrolle el paquete client:


o Copie los ficheros ClientUDP.java y Client.java del directorio de
descargas al workspace.
o Realice los ejercicios propuestos.
o Ejecute y depure Client.java utilizando el menú Run... y proporcionado
los parámetros de ejecución que sean necesarios.

5. Compruebe el correcto funcionamiento del cliente y servidores enviando


mensajes a servidores remotos desarrollados por sus compañeros (y
viceversa).

2.3 Realización de variantes de la práctica: servidor de hora

Partiendo del proyecto anterior, cree ahora dos aplicaciones (cliente y servidor),
en la que el servidor proporciona la hora y el día a los clientes que lo soliciten.

• El servidor puede obtener la hora utilizando la clase Date:

String fecha = new Date().toString();

• El programa cliente realizará una petición al servidor enviando un paquete con


el string: “Peticion hora clienteXX”, donde XX será un valor numérico que
identifique al cliente, y esperará la respuesta un tiempo limitado (5000
milisegundos). Para poder configurar un tiempo de espera (timeout) la clase
DatagramSocket dispone del método:

setSoTimeout(int timeout);

Pág: 5
DISCA-UPV ReSiDiCo

Cuando se fija un límite, el método receive se bloquea durante el tiempo


fijado y después, si no se ha recibido nada, lanza una excepción:

InterruptedIOException

• El programa cliente, si recibe la respuesta deberá enviar a la salida estándar el


día y la hora proporcionados por el servidor. Si después del tiempo de espera
configurado no recibiera una respuesta deberá enviar a la salida estándar un
mensaje de error.

2.4 Realización de variantes de la práctica: envío de objetos serializados

Hemos visto que las aplicaciones se comunican según el protocolo UDP mediante el
envío y recepción de datagramas que consisten básicamente en un buffer de bytes
que almacena el mensaje. Hasta ahora la información transmitida en las
comunicaciones entre clientes y servidores ha consistido únicamente en cadenas
de caracteres. Sin embargo, podríamos transmitir cualquier tipo de información
mediante su secuencia de bytes.

El objetivo de este apartado será transmitir entre las aplicaciones objetos java.
Para ello, deberemos convertir el objeto a transmitir en su secuencia de bytes, lo
cual se denomina serializar. Veremos cómo el lenguaje java nos permite hacerlo
de manera muy sencilla utilizando la interfaz Serializable.

• Partiendo de las aplicaciones cliente y servidor de hora realizadas


anteriormente, se modificarán de manera que ahora el servidor proporcionará
al cliente un objeto en lugar de una cadena de caracteres. Este objeto será una
instancia de una nueva clase denominada Hora que tendrá como atributos una
variable de tipo Date y un String con el eco del mensaje del cliente. De esta
manera, se enviará al cliente un objeto serializado de tipo Hora que contendrá
el eco de su mensaje y la hora.

1. Lo primero que haremos será crear en el proyecto un nuevo paquete


denominado data e incluiremos un nuevo fichero “Hora.java” donde se definirá
la nueva clase “Hora”:

package data;

import java.io.Serializable;
import java.util.Date;

public final class Hora implements Serializable


{
public String eco = null;
public Date date = null;

public Hora (String eco, Date date)


{
this.eco = eco;

Pág: 6
DISCA-UPV ReSiDiCo

this.date = date;
} // ctor

} // class Hora

Observe que para que los objetos que instancien esta clase puedan
convertirse en cadenas de bytes, la clase únicamente tiene que implementar la
interfaz Serializable definida en el lenguaje java.

2. A continuación modificaremos el servidor para que responda a las peticiones


de los clientes creando un objeto de clase Hora y serializándolo (obtener su
cadena de bytes) para poder enviarlo en el datagrama. Básicamente, para
poder obtener el buffer de bytes correspondiente a un objeto serializable, las
clases y pasos que proporciona java son:

Hora hora = new Hora(datosRecibidos, new Date());

ByteArrayOutputStream bos = new ByteArrayOutputStream();


ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject (hora);
byte[] buffer = bos.toByteArray();

Realice las modificaciones necesarias en el fichero “ServerUDP.java”.

3. Finalmente modificaremos el cliente para que, una vez recibido el datagrama,


obtenga el objeto enviado por el servidor mediante la des-serialización (el
proceso inverso a la serialización) del buffer de bytes recibido. Para ello, las
clases y pasos que proporciona java son:

byte[] buffer =new byte[4096];


……………………………
buffer = packet.getData ();

ByteArrayInputStream bis = new


ByteArrayInputStream(buffer);
ObjectInputStream ois = new ObjectInputStream(bis);
Object objetoRecibido = (Object) ois.readObject();

Una vez disponemos del objeto recibido, observar que se ha utilizado la clase
base Object de la que deriva cualquier objeto java, podemos hacer el cast a la
clase que realmente se corresponde y utilizar sus métodos. En el caso de
nuestro cliente, tendrá que acceder al atributo date para obtener el String de la
hora y visualizarlo por pantalla:

System.out.println(((Hora)ObjetoRecibido).date.toString());

Pág: 7
DISCA-UPV ReSiDiCo

Realice las modificaciones necesarias en los ficheros “ClientUDP.java” y


“Client.java”.

3. Incorporando una interfaz gráfica a nuestras aplicaciones


A continuación veremos cómo implementar una aplicación con interfaz gráfica o
GUI's (Graphical User Interface) en java. Para ello, utilizaremos un editor visual de
interfaces incorporada en el entorno de desarrollo (IDE) de Java, el
WindowBuilder editor.

3.1 Instalación de WindowsBuilder

Para instalar WindowsBuilder Pro Eclipse seleccionaremos en el menú principal


de eclipse la opción “Help->Install New Software…” que abrirá la ventana de
diálogo “Install”.

En la ventana de diálogo “Install” indicar en el campo “Work with:” la url desde


donde descargar los ficheros de instalación. Esta url dependerá de la versión de
eclipse que utilicemos, en la página https://eclipse.org/windowbuilder/ disponemos de
todas las opciones:

• Si utilizamos la versión de Eclipse 4.4 Luna


http://download.eclipse.org/windowbuilder/WB/release/R201506241200-1/4.4/

• Si utilizamos la versión de Eclipse 4.3 Kepler:


http://download.eclipse.org/windowbuilder/WB/release/R201406251200/4.3/

• Si utilizamos la versión de Eclipse 4.2 Juno:


http://download.eclipse.org/windowbuilder/WB/release/R201406251200/4.2/

Copiar y pegar la opción que corresponda en el campo “Work with:”.

Pág: 8
DISCA-UPV ReSiDiCo

Seleccionar todos los paquetes y pulsar en el botón “next” para proceder con la
instalación.

3.2 Uso de WindowsBuilder

Una vez instalado el editor WindowsBuilder los pasos para crear una aplicación con
interfaz gráfica son los siguientes:

1. En primer lugar se crea el proyecto java.


2. A continuación se crea la interfaz desde el menú “new->Other…” seleccionando
la opción “Application Window”dentro de WindowBuilder:

3. En el asistente se indica el nombre de la nueva clase con interfaz gráfica y el


paquete donde se ubicará:

Pág: 9
DISCA-UPV ReSiDiCo

4. El asistente crea un fichero java, en el caso del ejemplo AppGUI.java, con la


estructura de una aplicación que ya consiste en una ventana aunque todavía sin
componentes:

package appGUI;

import java.awt.EventQueue;
import javax.swing.JFrame;

public class AppGUI {

private JFrame frame;

/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
AppGUI window = new AppGUI();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}

/**
* Create the application.
*/
public AppGUI() {
initialize();
}

/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

Puede ejecutarse:

Pág: 10
DISCA-UPV ReSiDiCo

5. A partir de ahora, habrá que añadir los componentes a la nueva ventana y los
manejadores de los eventos. Puede hacerse directamente sobre el código o de
forma visual usando el editor gráfico que proporciona WindowsBuilder.

Para abrir un fichero java con el editor gráfico de WindowsBuilder, puede


seleccionar el fichero desde el package explorer de Eclipse con el botón derecho del
ratón y acceder a la opción del menú “Open With -> WindowsBuilder Editor”. El
editor ofrece una doble visión del fichero: código fuente y diseño gráfico:

Para realizar el diseño de una interfaz gráfica como la mostrada en la figura previa
deberá ir añadiendo elementos de la Palette de componentes gráficos. Deberá
tener en cuenta los siguientes aspectos:

• Seleccionar el Layout Manager null (Absolute loyout).

• Añada componentes gráficos seleccionándolos desde el menú de Swing


Components de la Palette. Se recomienda dar a los componentes nombres
fácilmente identificables (Properties -> Variable) en el momento de su
creación, especialmente aquellos que vayan a ser manipulados:
o botonEnviar
o textoHost
o textoEnviar
o textoRecibido
o barraEstado

3.2.1 Realización de los manejadores de eventos

Para realizar un manejador de un componente gráfico:

Pág: 11
DISCA-UPV ReSiDiCo

• Seleccione el componente en el editor gráfico y apriete el botón derecho del


ratón. En el menú contextual seleccionar Add event handler -> action. Se
creará en la ventana de código la siguiente plantilla de manejador:

jButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {

System.out.println("actionPerformed()");

}
);

Rellene la plantilla del manejador con el código que corresponda a cada


manejador.

4. Realización de una aplicación cliente-servidor basada en


UDP con interfaz gráfica
Como parte final de la práctica se propone desarrollar una aplicación con interfaz
gráfica que permita crear un socket UDP para enviar y recibir mensajes de texto. El
objetivo será ejecutar varias instancias de la aplicación y comunicarse entre ellas.
El interfaz de la aplicación será el siguiente:

Se realizarán manejadores para los siguientes eventos de tipo ActionEvent:

• Pulsación del botón “Crear Socket UDP”: el manejo consistirá en crear un


socket UDP vinculado al puerto especificado.

• Pulsación del botón “Enviar”: el manejo consistirá en enviar por el socket


creado el mensaje especificado a la dirección y puerto también especificados.

• Pulsación del botón “Iniciar hilo para Recibir”: el manejo consistirá en crear un
hilo que se encargará de recibir por el socket creado los mensajes.

Pág: 12
DISCA-UPV ReSiDiCo

El método receive de la clase DatagramSocket es bloqueante. Esto


quiere decir que el hilo que ejecuta el método se detiene hasta que finaliza
dicho método, que en el caso de receive será hasta la recepción del mensaje.
Observar que si se ejecutara en el hilo principal, la aplicación se detendría
hasta que se recibiera un mensaje. Por ello, crearemos un nuevo hilo para la
recepción de mensajes.

1. Cree un nuevo proyecto Cliente-Servidor-GUI-UDP en el workspace.

2. Cree un paquete de nombre clientserver que incluya un fichero java


ClientServerUDP.java que defina una nueva clase denominada
ClientServerUDP. Esta clase deberá ofrecer dos métodos para enviar y
recibir mensajes a través de un socket UDP. Implementar esta clase
basándose en el código desarrollado en los apartados anteriores de la
práctica. Para ello:

o En el constructor de la clase se proporcionará como parámetro el


número de puerto con el que se creará el DatagramSocket.
o La clase ofrecerá un método para enviar mensajes que tendrá como
parámetros: el mensaje a enviar y la dirección y puerto del servidor
a donde enviar el mensaje. El método utilizará el socket creado en el
constructor para enviar el mensaje.
o La clase ofrecerá otro método para recibir mensajes. El método
también utilizará el socket creado en el constructor para recibir el
mensaje.

3. Cree, utilizando el asistente de WindowsBuilder tal como se ha descrito


anteriormente, una clase con interfaz gráfica denominada AppGUI en un
paquete de nombre appGUI.

4. Edite gráficamente el fichero AppGUI.java y añada los componentes


gráficos necesarios para implementar la interfaz de la aplicación tal como
anteriormente se ha presentado (ver la figura).

5. Añada los manejadores necesarios asociados a la pulsación de cada uno de


los tres botones. El código que se incluya en el manejador del botón “Crear
Socket UDP” deberá instanciar un objeto de clase ClientServerUDP y el
código de los manejadores de los otros dos botones deberá utilizar los
métodos proporcionados por esta clase para enviar o recibir mensajes
según corresponda. En el caso del botón “Iniciar hilo para Recibir” habrá
que crear un nuevo thread que entrará en un bucle que llamara al método
receive de la clase DatagramSocket. Conforme este hilo vaya
recibiendo mensajes los mostrará en el campo “Mensajes:” de la ventana de
la aplicación.

Pág: 13
DISCA-UPV ReSiDiCo

6. Ejecutar varias instancias de la aplicación y enviarse mensajes entre ellas:

Si las instancias se ejecutan en la misma máquina, misma dirección IP, los


puertos vinculados deberán ser diferentes.

Observar que cuando la aplicación recibe un mensaje, ésta debería obtener la


dirección y puerto desde donde se envió el mensaje (métodos correspondientes
del DatagramPacket) para así escribirlos en los campos “Dir. IP:” y “Puerto:” de la
ventana asociados al botón “Enviar”. De esta manera el usuario de la aplicación, si
lo desea, podrá enviar lo que escriba en el campo “Mensaje:” como respuesta al
mensaje recibido.

Pág: 14

También podría gustarte