Socket programming with UDP

De Departamento de Informatica
Saltar a: navegación, buscar

Servicio de transporte no orientado a la conexión. Son más eficientes que TCP, pero en su utilización no está garantizada la fiabilidad. Los datos se envían y reciben en paquetes, cuya entrega no está garantizada. Los paquetes pueden ser duplicados, perdidos o llegar en un orden diferente al que se envió. Las comunicaciones a través de datagramas usan UDP (User Datagram Protocol), lo que significa que, cada vez que se envíen datagramas es necesario enviar el descriptor del socket local y la dirección del socket que debe recibir el datagrama. Como se puede ver, hay que enviar datos adicionales cada vez que se realice una comunicación, aunque tiene la ventaja de que se pueden indicar direcciones globales y el mismo mensaje llegará a un muchas máquinas a la vez.

Contenido

¿Qué es un Socket?

Los sockets son un sistema de comunicación entre procesos de diferentes máquinas de una red. Más exactamente, un socket es un punto de comunicación por el cual un proceso puede emitir o recibir información. Fueron popularizados por Berckley Software Distribution, de la Universidad norteamericana de Berkley. Los sockets han de ser capaces de utilizar el protocolo de streams TCP (Transfer Contro Protocol) y el de datagramas UDP (User Datagram Protocol).Utilizan una serie de primitivas para establecer el punto de comunicación, para conectarse a una máquina remota en un determinado puerto que esté disponible, para escuchar en él, para leer o escribir y publicar información en él, y finalmente para desconectarse.

Funcionamiento Generico

Normalmente, un servidor se ejecuta sobre una computadora específica y tiene un socket que responde en un puerto específico. El servidor únicamente espera, escuchando a través del socket a que un cliente haga una petición. En el lado del cliente: el cliente conoce el nombre de host de la máquina en la cual el servidor se encuentra ejecutando y el número de puerto en el cual el servidor está conectado. Para realizar una petición de conexión , el cliente intenta encontrar al servidor en la máquina servidora en el puerto especificado. Si todo va bien, el servidor acepta la conexión. Además de aceptar, el servidor obtiene un nuevo socket sobre un puerto diferente. Esto se debe a que necesita un nuevo socket (y , en consecuencia, un numero de puerto diferente) para seguir atendiendo al socket original para peticiones de conexión mientras atiende las necesidades del cliente que se conectó. Por la parte del cliente, si la conexión es aceptada, un socket se crea de forma satisfactoria y puede usarlo para comunicarse con el servidor. Es importante darse cuenta que el socket en el cliente no está utilizando el número de puerto usado para realizar la petición al servidor. En lugar de éste, el cliente asigna un número de puerto local a la máquina en la cual está siendo ejecutado. Ahora el cliente y el servidor pueden comunicarse escribiendo o leyendo en o desde sus respectivos sockets.

Sockets UDP

Funciones de la Programacion Socket con UDP

Los sockets UDP son sockets no orientados a conexión. Esto quiere decir que un programa puede abrir un socket y ponerse a escribir mensajes en él o leer, sin necesidad de esperar a que alguien se conecte en el otro extremo del socket. El protocolo UDP, al no ser orientado a conexión, no garantiza que el mensaje llegue a su destino. A modo de ejemplo, si se tiene un programa que envía un mensaje y no hay nadie escuchando, ese mensaje se pierde, sin embargo, aunque haya alguien escuchando, el protocolo tampoco garantiza que el mensaje llegue. Lo único que garantiza es, que si llega, llega sin errores.

Características generales de la programacion con sockets UDP

  • Cliente: envía directamente datagramas al servidor, queda a la espera de respuesta.
  • Servidor: lee datagramas de cola de espera, procesa y responde a los clientes y vuelve a la cola y lee el datagrama siguiente (servidor iterativo).
  • UDP: protocolo de transporte no orientado a conexión y que no garantiza ni la entrega ni el orden en que dichos datagramas son enviados.
  • Aplicación cliente/servidor deberá tener en cuenta las características del protocolo.
  • Aplicaciones UDP: DNS, NFS, SNMP, VoIP (y en general de distribución), difusión (multidestino).

Utilidad de los Sockets UDP

  • Este tipo de sockets se suele usar para información no vital, por ejemplo, envío de gráficos a una pantalla. Si se pierde algún gráfico por el camino, veremos que la pantalla pierde un refresco, pero no es importante. El que envía los gráficos puede estar dedicado a cosas más importantes y enviar los gráficos sin preocuparse (y sin quedarse bloqueado) si el otro los recibe o no.
  • Otra ventaja es que con este tipo de sockets es que un programa puede recibir mensajes de varios sitios a la vez. Si se esta escuchando por un socket no orientado a conexión, cualquier otro programa en otro computador puede enviarle un mensaje. El programa servidor no necesita preocuparse de establecer y mantener conexiones con varios clientes a la vez .

Aplicación

La siguiente Aplicación de programacion socket UDP esta realizada en Java, en resumen se tiene un cliente que envía 10 mensajes y el servidor los escribe en pantalla:

Instrucciones de compilación

Para compilar solo copie estos 4 archivos respetando el nombre en una misma carpeta, ahora en la misma carpeta ejecute javac *.java, listo!

Instrucciones de Ejecucion

Abra dos consolas, en una consola ejecute: java ServidorUdp, y en otra ejecute: java ClienteUdp, Listo!.


  • ServidorUdp.java
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
 * Servidor de udp que se pone a la escucha de DatagramPacket que contengan
 * dentro DatoUdp y los escribe en pantalla.
*/
public class ServidorUdp
{
   /**
    * Prueba del prorama ServidorUdp
    * 
    * @param args
    */
   public static void main(String[] args)
   {
       new ServidorUdp();
   }
   /**
    * Crea una instancia de esta clase, poniendose a la escucha del puerto
    * definido en Constantes y escribe en pantalla todos los mensajes que le
    * lleguen.
    */
   public ServidorUdp()
   {
       try
       {
           // La IP es la local, el puerto es en el que el servidor esté 
           // escuchando.
           DatagramSocket socket = new DatagramSocket(
                   Constantes.PUERTO_DEL_SERVIDOR, InetAddress
                           .getByName("localhost"));
           // Un DatagramPacket para recibir los mensajes.
           DatagramPacket dato = new DatagramPacket(new byte[100], 100);
           // Bucle infinito.
           while (true)
           {
               // Se recibe un dato y se escribe en pantalla.
               socket.receive(dato);
               System.out.print("Recibido dato de "
                       + dato.getAddress().getHostName() + " : ");
               // Conversion de los bytes a DatoUdp
               DatoUdp datoRecibido = DatoUdp.fromByteArray(dato.getData());
               System.out.println(datoRecibido.cadenaTexto);
           }
       } catch (Exception e)
       {
           e.printStackTrace();
       }
   }
}
  • ClienteUdp.java
/**
* Ejemplo de uso de socket udp en java
*/
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* Abre un socket udp y envía por él 10 mensajes consistentes en 10 clases
* DatoUdp.
*
*/
public class ClienteUdp
{
   /**
    * Programa de prueba. Instancia esta clase
    * @param args
    */
   public static void main(String[] args)
   {
       new ClienteUdp();
   }
   /**
    * Crea una instancia de esta clase y envía los 10 mensajes
    *
    */
   public ClienteUdp()
   {
       try
       {
           // La IP es la local, el puerto es en el que este cliente esté
           // escuchando.
           DatagramSocket socket = new DatagramSocket(
                   Constantes.PUERTO_DEL_CLIENTE, InetAddress
                           .getByName("localhost"));
           // Se instancia un DatoUdp y se convierte a bytes[]
           DatoUdp elDato = new DatoUdp("hola");
           byte[] elDatoEnBytes = elDato.toByteArray();
           // Se meten los bytes en el DatagramPacket, que es lo que se
           // va a enviar por el socket.
           // El destinatario es el servidor.
           // El puerto es por el que esté escuchando el servidor.
           DatagramPacket dato = new DatagramPacket(elDatoEnBytes,
                   elDatoEnBytes.length, InetAddress
                           .getByName(Constantes.HOST_SERVIDOR),
                   Constantes.PUERTO_DEL_SERVIDOR);
           // Se envía el DatagramPacket 10 veces, esperando 1 segundo entre
           // envío y envío.
           for (int i = 0; i < 10; i++)
           {
               System.out.println("Envio dato " + i);
               socket.send(dato);
               Thread.sleep(1000);
           }
       } catch (Exception e)
       {
           e.printStackTrace();
       }
   }
}
  • DatoUdp.java
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class DatoUdp implements Serializable
{
   /**
    * serial uid
    */
   private static final long serialVersionUID = 3258698714674442547L;
   /**
    * Crea una instancia de la clase, guardando la cadena que se le pasa.
    * @param cadena
    */
   public DatoUdp (String cadena)
   {
       this.cadenaTexto=cadena;
   }
   public String cadenaTexto;
   /**
    * Se autoconvierte esta clase a array de bytes.
    * @return La clase convertida a array de bytes.
    */
   public byte [] toByteArray()
   {
       try
       {
            // Se hace la conversión usando un ByteArrayOutputStream y un
            // ObjetOutputStream.
           ByteArrayOutputStream bytes = new ByteArrayOutputStream();
           ObjectOutputStream os = new ObjectOutputStream (bytes);
           os.writeObject(this);
           os.close();
           return bytes.toByteArray();
       }
       catch(Exception e)
       {
           e.printStackTrace();
           return null;
       }
   }
   /**
    * Se convierte el array de bytes que recibe en un objeto DatoUdp.
    * @param bytes El array de bytes
    * @return Un DatoUdp.
    */
   public static DatoUdp fromByteArray (byte [] bytes)
   {
       try
       {
           // Se realiza la conversión usando un ByteArrayInputStream y un
           // ObjectInputStream
           ByteArrayInputStream byteArray = new ByteArrayInputStream(bytes);
           ObjectInputStream is = new ObjectInputStream(byteArray);
           DatoUdp aux = (DatoUdp)is.readObject();
           is.close();
           return aux;
       }
       catch(Exception e)
       {
           e.printStackTrace();
           return null;
       }
   }
}
  • Constantes.java
/** Constantes para el ejemplo de envío y recepción con socket udp. */
public class Constantes
{
   /** Puerto en el que escucha el servidor. */
   public static final int PUERTO_DEL_SERVIDOR=5557;
   
   /** Puerto en el que escucha el cliente */
   public static final int PUERTO_DEL_CLIENTE=5558;
   
   /** Host en el que está el servidor */
   public static final String HOST_SERVIDOR="localhost";
   
   /** Host en el que está el cliente */
   public static final String HOST_CLIENTE="localhost";
}

Referencias

Herramientas personales
Espacios de nombres
Variantes
Acciones
Navegación
Herramientas