viernes, 26 de octubre de 2012

Implementación en JAVA (Sockets)

1.1.1.        La clase URL
Para comenzar con la programación de sockets, resulta necesario comprender las clases que ofrece Java. En primer lugar, la clase URL contiene constructores y métodos para la manipulación de URL (Universal Resource Locator): un objeto o servicio  en  Internet.  El  protocolo  TCP necesita  dos  tipos de información: la dirección IP y el número de puerto. Vamos a ver como podemos recibir entonces la página Web siguiente:

http://www.yahoo.com

En primer lugar, Yahoo tiene registrado su nombre, permitiendo que se use yahoo.com como su dirección IP, o lo que es lo mismo, cuando indicamos yahoo.com es como si hubiésemos indicado 205.216.146.71, su dirección IP real.

Si queremos obtener la dirección IP real de la red en que estamos corriendo, podemos realizar llamadas a los métodos getLocalHost() y getAddress(). Primero, getLocalHost() nos devuelve un objeto iNetAddress, que si usamos con getAddress() generará un array con los cuatro bytes de la dirección IP, por ejemplo:

InetAddress direccion = InetAddress.getLocalHost();
byte direccionIp[] = direccion.getAddress();

Si la dirección de la máquina en que estamos corriendo es 150.150.112.145, entonces:

direccionIp[0] = 150 direccionIp[1] = 150 direccionIp[2] = 112 direccionIp[3] = 145

Por otro lado, podemos especificar las partes que componen una url y así podríamos construir un objeto de tipo url utilizando los siguientes constructores:

URL (“http","www.yahoo.com","80","index.html”);

o  dejar  que  los  sistemas  utilicen  todos  los  valores  por  defecto  que  tienen definidos, como en:

URL (“http://www.yahoo.com”);

Y en los dos casos obtendríamos la visualización de la página principal de Yahoo en nuestro navegador.

1.1.2.        Arquitectura de comunicaciones
En Java, crear una conexión socket TCP/IP se realiza directamente con el paquete java.net. A continuación mostramos un diagrama de lo que ocurre en el lado del cliente y del servidor:



Networking en JAVA (Utilización de Sockets)

1.1.1.        Introducción a la programación con Sockets
Java proporciona dos formas diferentes de atacar la programación de comunicaciones a través de red, al menos en lo que a la comunicación web concierne. Por un lado están las clases Socket, DatagramSocket y ServerSocket, y por otro lado están las clases URL, URLEncoder y URLConnection.

Los sockets son puntos finales de enlaces de comunicaciones entre procesos. Los procesos los tratan como descriptores, de forma que se pueden intercambiar datos con otros procesos transmitiendo y recibiendo a través de sockets. El tipo de sockets describe la forma en la que se transfiere información a través de ese socket.

1.1.2.        Que son los Stream Sockets (TCP)
Son un servicio orientado a conexión, donde los datos se transfieren sin encuadrarlos en registros o bloques. Si se rompe la conexión entre los procesos, éstos serán informados de tal suceso para que tomen las medidas oportunas.

El  protocolo  de  comunicaciones  con  streams  es  un  protocolo  orientado  a conexión, ya que para establecer una comunicación utilizando el protocolo TCP, hay que establecer en primer lugar una conexión entre un par de sockets. Mientras uno de los sockets atiende peticiones de conexión (servidor), el otro solicita una conexión (cliente). Una vez que los dos sockets estén conectados, se pueden utilizar para transmitir datos en ambas direcciones.

1.1.3.        Que son los Datagram Sockets (UDP)
Son un servicio de transporte sin 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ó.

El protocolo de comunicaciones con datagramas es un protocolo sin conexión, es decir, 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.

Identificación de procesos (Networking)


1.1.1.        Que es una dirección IP
Una dirección IP es un número que identifica de manera lógica y jerárquica a una interfaz de un dispositivo (habitualmente una computadora) dentro de una red que utilice el protocolo IP (Internet Protocol), que corresponde al nivel de red del protocolo TCP/IP. Dicho número no se ha de confundir con la dirección MAC que es un número hexadecimal fijo que es asignado a la tarjeta o dispositivo de red por el fabricante, mientras que la dirección IP se puede cambiar.

Es habitual que un usuario que se conecta desde su hogar a Internet utilice una dirección IP. Esta dirección puede cambiar cada vez que se conecta; y a esta forma de asignación de dirección IP se denomina una dirección IP dinámica (normalmente se abrevia como IP dinámica).

Los sitios de Internet que por su naturaleza necesitan estar permanentemente conectados, generalmente tienen una dirección IP fija (se aplica la misma reducción por IP fija o IP estática), es decir, no cambia con el tiempo. Los servidores de correo, DNS, FTP públicos, y servidores de páginas web necesariamente deben contar con una dirección IP fija o estática, ya que de esta forma se permite su localización en la red.

1.1.2.        Que es un puerto
Un puerto es una dirección numérica a través de la cual se procesa un servicio, es decir, no son puertos físicos semejantes al puerto paralelo para conectar la impresora, sino que son direcciones lógicas proporcionadas por el sistema operativo para poder responder.

Las comunicaciones de información relacionada con Web tienen lugar a través del puerto 80 mediante protocolo TCP. Para emular esto en Java, se utiliza la clase Socket.

Teóricamente hay 65535 puertos disponibles, aunque los puertos del 1 al 1023 están reservados al uso de servicios estándar proporcionados por el sistema, quedando el resto libre para utilización por las aplicaciones de usuario. De no existir los puertos, solamente se podría ofrecer un servicio por máquina. Nótese que el protocolo IP no sabe nada al respecto de los números de puerto.

Introducción a Networking

1.1.1.        Que es Networking
El termino Networking se refiere a la posibilidad de trabajar con diversas aplicaciones ubicadas físicamente en distintas estaciones de trabajo y permitir que se conecten vía una red, para trabajar de manera cooperativa o simplemente enviar y recibir información.

1.1.2.        Que es un socket
Un Socket es una representación abstracta del extremo (endpoint) en un proceso de comunicación. Para que se dé la comunicación en una Red, el proceso de comunicación requiere un Socket a cada extremo Emisor/Receptor y viceversa.



La comunicación con sockets sigue el modelo Cliente/Servidor/Cliente. En la mayoría  de los  casos  un programa  Servidor fundamentalmente  envía  datos, mientras que un programa Cliente recibe esos datos, aunque es raro que un programa exclusivamente reciba o envíe datos. Una distinción confiable se logra si consideramos Cliente al programa que inicia la comunicación y Servidor al programa que espera a que algún otro iniciecomunicación con él.

viernes, 19 de octubre de 2012

Ejemplo de señalización ( wait() y notify() )

En este ejemplo vamos a tener 3 clases: una clase Main, una clase Saludo y una clase Personal (Hilo).

Clase Main:

public class Main {
   
    public static void main(String[] args) {
       
        // Objeto en comun, se encarga del wait y notify
        Saludo s = new Saludo();
       
        /*Instancio los hilos y le paso como parametros:
         *

Ejemplo exclusión mutua (synchronized)

En este ejemplo vamos a tener 3 clases: una clase Main, una clase CuentaBanco y una clase VerificarCuenta (Hilo).

Clase Main:

public class Main {
    public static void main(String[] args) {
       
        VerificarCuenta vc = new VerificarCuenta();
       
        Thread Luis = new Thread(vc, "Luis");
        Thread Manuel = new Thread(vc, "Manuel");
       
        Luis.start();
        Manuel.start();
    }
}

Sincronización (Threads)


La importancia de la sincronización
La programación concurrente puede dar lugar a muchos errores debido a la utilización de recursos compartidos que pueden ser alterados. Las secciones de código potencialmente peligrosas de provocar estos errores se conocen como secciones críticas.

En general los programas concurrentes deben ser correctos totalmente. Este concepto es la suma de dos conceptos distintos de la corrección parcial(o safety) esto es que terminara en algún momento de tiempo finito. En esto programas por lo tanto hay que evitar que varios hilos entren en una sección critica (exclusión mutua o mutex) y que los programas se bloqueen (deadlock).

Planificación de Threads (Prioridades)


Que significa planificación
Un tema fundamental dentro de la programación multihilo es la planificación de los hilos. Este concepto se refiere a la política a seguir de que hilo toma el control del procesador y cuando. Obviamente en el caso de que un hilo este bloqueado esperando una operación de I/O este hilo debería dejar el control del procesador y que este control lo tomara otro hilo que si pudiera hacer uso del tiempo de CPU. ¿Pero que pasa si hay más de un hilo esperando? ¿A cual de ellos le otorgamos el control del procesador?

Prioridades
Para determinar que hilo debe ejecutarse primero, cada hilo posee su propia prioridad: un hilo de prioridad mas alta que se encuentre en el estado LISTO entrara antes en el estado EN EJECUCION que otro de menor prioridad.

El método setPriority()
Para establecer la prioridad de un thread se utiliza el método setPriority() de la siguiente manera:

Estados de un Thread


Estado Nuevo
El Thread ha sido creado pero no inicializado, es decir, no se ha ejecutado todavía el método start(). Se producirá un mensaje de error (IllegalThreadStateException) si se intenta ejecutar cualquier método de la clase Thread distinto de start().

Estado Ejecutable
El Thread puede estar ejecutándose, siempre y cuando se le haya asignado un determinado tiempo de CPU. En la practica puede no estar siendo ejecutado en un instante determinado en beneficio de otro thread.

Estado Bloqueado
El Thread podría estar ejecutándose, pero hay alguna actividad interna suya que lo impide, como por ejemplo una espera producida por una operación de escritura o lectura de datos por teclado (E/S). Si un Thread esta en este estado, no se le asigna tiempo de CPU.

Controlando los Threads (Ciclo de vida)


Que es el ciclo de vida
El ciclo de vida de un Thread representa los estados por los cuales puede pasar un Thread desde que nace hsta que muere. Durante el ciclo de vida de un Thread, este se puede encontrar en diferentes estados. La figura siguiente muestra estos estados y los métodos que provocan el paso de un estado a otro.

Diagrama de ciclo de vida

















- Para ver un diagrama mas detallado del ciclo de vida de un Thread ver la entrada "Estados de un Thread" Ciclo de Vida Extendido -

Método Deprecados (Desaconsejados) - Threads -

El método stop(), que ocasiona el lanzamiento de la excepción ThreadDeath en el thread destino. La excepción se genera sea cual sea el método que está ejecutando el thread. La idea es que la excepción no se capture, de modo que vaya subiendo en la pila de llamadas de el thread destino, hasta llegar al método run(), que tampoco la capturaría, finalizando la ejecución de el Thread. La excepción ThreadDeath es la única que es ignorada por el método uncaughtException(...) de la clase ThreadGroup, de modo que el usuario no recibe ningún mensaje en la salida de error por culpa de dicha excepción.
        ThreadDeath hereda intencionadamente de Error, en lugar de Exception, pues lo que se quiere es que no sea capturada, y como existe el uso generalizado de la construcción:

    try {
       ...
    }
    catch (Exception e) {
       ...
    }


         prefirieron que ThreadDeath no heredara de Exception, a pesar de que no entra dentro de la filosofía de la clase Error.

Manejo de Threads (Metodos)

Los métodos start() y run()
Como habíamos mencionado antes, para poner en marcha este nuevo Thread se debe llamar al método start(), heredado de  la súper-clase Thread, que se encarga de llamar a run(). Es importante no confundir el método start() con el método run(). El método run() contiene el código a ser ejecutado “asincrónicamente” en otro thread, mientras que el método start() es el que crea al Thread y en algún punto hace que ese Thread ejecute lo que esta en run(). Este método devuelve el control inmediatamente. Pero si mezclamos todo y ejecutamos directamente el run(), el código se ejecutara en el Thread actual.

El método start() devuelve el control inmediatamente… mientras tanto, el nuevo Thread inicia su recorrido por el método run(). ¿Hasta cuando? Hasta que termina ese método, cuando sale, termina el Thread.

El método join()
Si un Thread necesita esperar a que otro termine (por ejemplo el Thread padre espera a que termine el hijo) puede usar el método join(). ¿Por que se llama así? Crear un proceso es como una bifurcación, se abren 2 caminos, que uno espere a otro es lo contrario, una unificación.

Creación de Threads

Alternativas de creación
En Java hay dos formas de crear nuevos threads. La primera de ellas consiste en crear una nueva clase que herede de la clase  java.lang.Thread y sobrecargar el método run() de dicha clase. El segundo método consiste en declarar una clase que implemente la interfaz java.lang.Runnable, la cual declarara el método run(); posteriormente se enviara dicho objeto a la clase Thread.

En este caso, se ha creado la clase MiClase, que hereda de Thread y después haremos lo mismo pero implementando Runnable. La principal actividad del thread, es que escriba 10 veces el nombre del thread creado.

Para poner en marcha este nuevo thread se debe llamar la método start(), heredado de la súper-clase Thread, que se encarga de llamar a run().

Introducción a Threads


Que es un Thread (Hilo de Ejecución).
Un concepto fundamental en programación es la idea de manejar más de una tarea a la vez. Muchos problemas de programación requieren que el programa pueda detener lo que este haciendo, tratar con algún otro problema y regresar al proceso principal.

Dentro de un programa, las partes que corren separadamente se llaman hilos (Thread) y el concepto general se llama Multithreading.

Ordinariamente, los hilos son una manera de asignar el tiempo de un solo procesador. Pero si el sistema operativo apoya procesadores múltiples, cada hilo puede asignarse a