Distribución en Java Concurrencia y Distribución Programación Avanzada Posgrado en Ciencia e Ingeniería de la Computación, UNAM. Introducción TCP/IP es un conjunto de protocolos que permite a dos programas comunicarse sobre un canal de comunicación, Esto se logra mediante crear una conexión de datos entre los dos programas. Una vez establecida, la conexión es vista por los dos programas como un archivoal cual el emisor escribe y el receptor lee. Un canal de comunicación bidireccional se estable mediante permitir a los dos programas la lectura y escritura del archivo. El proceso se ilustra en la Figura, donde un programa cliente establece contacto con un programa servidor, ambos ejecutándose en dos computadoras diferentes. Mediante esta aproximación, es posible ennviar transacciones a ser procesadas en otras máquinas. Computadora Cliente Computadora Servidor Programa Cliente Programa Servidor Figura : Cliente y sevidor. La siguiente tabla resume las responsabilidades de un cliente y un servidor:
Cliente Servidor Una aplicación o applet cliente envía transacciones a una aplicación o applet servidor para su procesamiento. Una aplicación o applet servidor procesa las transacciones de parte de uno o más clientes. 2. Conceptos y términos 2.. Nombres de máquina y localhost Cada máquina conetada a Internet sae reconoce por una dirección IP única. Esta es en realidad un número entero de 32 bits que se escribe en forma de cuatro octetos de la forma 92.62.83.86. Sin embargo, como esto es una forma muy poco amigable de nombrar computadoras, se utiliza en lugar de esto un nombre simbólico de dominio. Un ejemplo de nombre de dominio es hp.fciencias.unam.mx, y se lee como la máquina hp está en el dominio fciencias, que se encuentra en el dominio unam, del dominio mx. Los dominios de más alta jerarquía se registran por acuerdo internacional, los niveles más balos por organizaciones o por personas responsables de tal dominio. Utilizando esta estrategia cada computadora del mundo tiene un único nombre de dominio que puede ser relativamente fácil de recordar. Por otro lado, en muchos sistemas de cómputo, el nombre de la computadora local tiene el alias de localhost. De tal modo, si se desea comunicarse con otra aplicación o applet que se ejecuta en la misma computadora, entonces es posible utilizar el nombre localhost como el nombre de la máquina. Esto permite probar programas que utilizan la red sin necesidad de conectar la computadora a la red. Por supuesto, es necesario que el software de redes necesario debe estar instalado en la computadora para que esto funcione. 2.2. Puertos Como puede haber muchos programas ejecutándose en una computadora individual, se utiliza un número de puerto lógico como identificador único del programa con que el usuario desea comunicarse. Un número de puerto se representa por un número entero dentro del rango de y 65536. Los números de puerto entre y 024 se reservan para programas específicos, de modo que debe evitarse su uso. Por ejemplo, el conjunto de programas FTP utilizan los puertos 20 y 2 para comunicar clientes y servidores FTP. 2
Utilizar uno de estos puertos puede cancelar el uso del cliente FTP de la máquina local, así como obtener resultados extraños cuando el programa se comunica con otras máquinas. Desafortunadamente, algunos de los puertos numerados fuera del rango a 024 también se utilizan por otros programas. 2.3. Cliente Un programa cliente es aquél que solicita al servidor realizar una tarea de por su parte. El cliente inicia la conversación con el servidor. Un cliente ligero realiza muy poca labor local, delegando la mayoría del trabajo al servidor, mientras que un cliente pesado hace la mayor parte del trabajo por sí mismo. 2.4. Servidor Un programa servidor es aquél que realiza tareas de parte de sus clientes. El servidor puede comunicarse con el cliente para retornar resultados de su solicitud. 2.5. Socket Un socket es un extremo o punto de conexiones para communicación entre dos programas. En esencia, el socket es la conexión entre dos programas desde el punto de vista del programador. La creación de un socket sucede en dos casos principalmente: Cuando un cliente se conecta a un socket como una conexión a un puerto dado en una máquina dada. Cuando un servidor se conecta a un socket que se conecta a un puerto dado en la máquina anfitrión (host machine). Esta conexión resulta incompleta, y se completará solamente cuando un cliente se conecte a tal puerto. 2.6. Resumen La Figure 2 muestra cómo dos computadoras beta y gamma ejecutan programas cliente (programas B y C) que se comunican con un programa servidor (programa A) ejecutándose en el servidor alfa. Estas computadoras se encuentran todas en el dominio fciencias.unam.mx. 3
beta.fciencias.unam.mx alfa.fciencias.unam.mx Programa B Programa A S Cliente Servidor S 99 gamma.fciencias.unam.mx S Socket Programa C 99 Puerto S Cliente Figura 2: Dos clientes y un servidor. Los dos programas cliente crean un socket local que conectan al puerto 99 en la máquina con el nombre de dominio alfa.fciencias.unam.mx. Esta computadora ejecuta un programa servidor (programa A) que está constantemente escuchando el puerto 99, en espera de conexiones. Algunos de los principales conceptos de distribución se resumen en la siguiente tabla: 4
Dirección Actualmente, un IPv4 (IP versión 4) usa un valor entero IP de 32 bits para la dirección normalmente escrita como 4 bytes de la forma: 92.62.83.86. Nótese que el formato de una dirección IP se expandirá a IPv6, permitiendo direcciones de 28 bits, lo que permitirá un mayor número de computadoras conectadas a Internet. Nombre Nombre simbólico de una máquina o grupo de máquinas. de dominio Cada dueño de un dominio puede registrar otros nombres en ese dominio. Por ejemplo, la UNAM (unam.mx) puede elegir los nombres de sus máquinas y otros sub-dominios en su dominio. Cada dominio usualmente tiene un DNS (Domain Name Server) que mapea el nombre de cada máquina en su dominio a la dirección IP real. Un DNS es una computadora que es capaz de proveer una dirección IP para un nombre de dominio o solicitar a otro DNS que provea de esta información. TCP Transport Control Protocol. Un protocolo que garantiza que cuando se establece y mantiene abierta una conexión, la máquina receptora recibirá los mensajes que se le envían. El mensaje se divide en paquetes, que recorren cualquier ruta a su destino. Sin embargo, el protocolo TCP asegura el re-ensamble de todos los paquetes individuales en el orden correcto para entregarlo al receptor. UDP User Datagram Protocol. En este protocolo, el mensaje se divide en paquetes y se envían al destino, pero no hay ninguna garantía de que los paquetes llegarán en el order correcto, o al menos llegarán. IP Internet Protocol. Una colección de protocolos de los que TCP y UDP son miembros. Número Número en el rango de a 65536. Ejemplos de números de de puerto puerto utilizados son: 20 y 2, usados por FTP, 23, para telnet, y 79, para finger. Host La máquina o computadora en la que el programa se ejecuta. 3. La implementación Desarrolle dos programas, uno cliente y uno servidor, para implementar un chatline simple, utilizando una interfaz gráfica de usuario (GUI). Este programa permite a varias personas intercambiar mensajes atrvés de Internet. Cada usuario del chatline ejecuta un programa cliente que envía 5
mensajes a un programa servidor central, y este re-envía estos mensajes a todos los clientes. Este proceso se muestra en la Figura 3. Cliente Cliente 2 Servidor Cliente n El servidor re envia a cada cliente cualquier mensaje que se le envie. Los clientes mandan mensajes al servidor, deslegando los mensajes que el servidor les envia. Figura 3: Un chatline. Una ilustración de dos personas interactuando mediante el chatline se muestra en la Figure 4. 3.. La clase Client El cliente del chatline se compone de las siguientes clases: Clase Resumen Application Crea y maneja los componentes de comunicación. Client Inicia al cliente. TextArea El área de texto visual. NetReader Lee información del servidor remoto. NetWriter Escribe información en el servidor remoto. TextField Componente visual. Transaction Objeto que responde a una instancia de un TextField. El diagrama de clases se muestra en la Figura 5. La interfaz gráfica de usuario se implementa mediante crear la clase Application como una subclase de la clase Frame, que contiene los objetos 6
Maquina mc0.local Maquina mc.local mc0.local:2000(mike) started Mike: Alguien por ahi? cori: Si, yo... mc.local:2000(cori) started Mike: Alguien por ahi? cori: Si, yo... Alguien por ahi? Si, yo... Figura 4: Dos personas comunicándose mediate el puerto 2000. Client Application NetReader TextArea NetWriter Transaction TextField Figura 5: Diagrama de clases del cliente. 7
utilizados en la interfaz gráfica. De tal modo, el constructor de la clase Application debe establecer dos ventanas: Una ventana de salida, theoutput, intancia de la clase TextArea Una ventana de entrada, theinput, instance de la clase TextField La ventana de salida se utliza para desplegar las conversasiones que actualmente se llevan a cabo en el chatline, mientras que la ventana de entrada se usa para que el usuaro local pueda contribuir a la conversación. El ciclo principal de el proceso debe estar contenido en un método start(), que permite leer los mensajes que se reciben del servidor, y desplegarlos en la ventana de salida. Esto sólo puede realizarse si se ha establecido una conexión. Para ello, el nombre de la máquina, el puerto y el nombre del usuario debe proveerse como parámetros de la línea de comando, utilizando un método llamado params(). Este método debe implementarse de modo que decodifique los parámetros de la línea de comandos, y si encuentra alguna inconsistencia, debe proveer un valor por defecto apropiado. Otro método, setupconnect(), debe implementarse para establecer la conexión con la máquina servidor,, a través de un socket. Finalmente, la clase Transaction implemlementa la acción en la ventana de entrada, implementando la interfaz ActionListener. Esto requiere la implementación del método actionperformed(), que se ejecuta cada vez que el usuario escribe un mensaje y presiona enter. 3.2. La clase Server El servidor lee los mensajes de texto de los clientes y los reenvía a todos aquéllos que se encuentren actualmente conectados. El servidor del chatline se compone, entonces, de las siguientes clases: Clase Resumen NetReader Lee información del servidor remoto. NetWriter Escribe información en el servidor remoto. Person Crea un objecto activo que se comunica con el cliente. Server Inicia el servidor. TChatManager Maneja la comunicación entre el cliente y el servidor. TClientReader Crea un objeto activo para leer información del cliente y provee una interfaz para leer información. 8
En esencia, el servidor crea múltuiples instancias de la clase Person para manejar a los usuarios individuales. Una instancia de la clase TChatManager es un objecto activo que maneja el flujo de mensajes entre los usuarios individuales. El diagrama de clases de la Figura 6 muestra la organización del servidor. Server * Person * TClientReader NetReader TChatManager NetWriter Figura 6: Diagrama de clases del servidor. La clase Server debe implementar el ciclo principal de ejecución del servidor chatline. En esencia, los usuarios hacen contacto con este servidor. Por cada contacto, un objecto activo debe ser creado para controlar la comunicación con cada usuario. Además, un proceso por separado debe crearse para polear cada usuario en turno para ver si han hecho contacto con el servidor para enviar un mensaje, si lo han hecho, y entonces distribuirlo a todos los usuarios. 3.3. La clase TChatManager La clase TChatManager debe implementarse para controlar las instancias de la clase Person. Cada instancia de la clase Person es un objeto activo que se mantiene mediante un arreglo thechatters, de tamaño MAXPERSONS. El paper de una instancia de la clase Person es comunicarse con cada usuario del chatline. La clase TChatManager debe contar con un método add() que añada un nuevo usuario a su colección de usuarios. Este debe ser un método sincronizado para prevenir la corrupción y/o mal uso de thechatters como 9
recurso conpartido. El arreglo thechatters debe permitir añadir y accesar a differentes threads ejecutándose concurrentemente. Nótese que, en caso de que ae haya alcanzado el número máximo de usuarios, un nuevo usuario simplemente no puede conectarse. Otro método de la clase TChatManager es remove(), que se encarga de remover a un usuario inactivo de la colección de usuarios. Varios otros métodos son necesarios para un funcionamiento adecuado: el método getmessage() debe retornar un mensaje desde un usuario; si el usuario no ha transmitido ningún mensaje, entonces debe retornar un valor null. Este método es sincronizado, ya que cada usuario de la colección de usuarios thechatters es un objeto activo que contínuamente monitorea la línea de comunicación entre sí mismo y su cliente. Otro método getname() simplemente debe retornar el nombre del usuario. El métdodo putmessage() debe escribir un mensaje al usuario. El método sendtoall() envía un mensaje a todos los usuarios, incluyendo al emisor. Finalmente, el método run() debe implementar la parte activa del objeto, que es un ciclo contínuo, poleando cada usuario por turno para ver si ha enviado un mensaje de texto. Si así es, entonces el mensaje de texto se re-envía a todos los usuarios. Si el nombre del usuario no se conoce, entonces el nombre que se envía como parte del mensaje de texto debe utilizarse como el nombre del usuario. Si el usuario ha salido del chatline, un mensaje EOF debe recibirse, en cuyo caso los demás usuarios reciben un mensaje informando que tal usuario ha salido de la sesión. 3.4. La clase Person La clase Person debe utilizarse para crear objetos activos que contínuamente monitorean la conexión de comunicación del cliente, buscando un nuevo mensaje de texto. Esto se implementa como una funcionalidad de una instancia de la clase TClientReader. En esencia, la clase Person debe proveer de una interfaz limpia a los objetos responsables de leer y escribir los canales de comunicación. Debe contar con métdos para manipular líneas de texto: getline(), putline(), setname() y getname(). 0
3.5. La clase TClientReader La clase TClientReader debe crear un objeto activo que continuamente monitoree la línea de comunicación entre un usuario, esperando un mensaje de texto para enviar. De tal modo, este proceso no debe bloquearse, para lo que se utiliza un buffer unitario para almacenar el mensaje de texto recibido. Se checa el buffer por un mensaje, en lugar de por una comunicación. De tal modo, puede hacerse una solicitud no-bloqueable para ver si el buffer contiene un mensaje. Como la espera de un mensaje de texto en el canal de comunicaciones es una operación que si puede bloquearse, esta funcionalidad debe llevarse a cabo por la parte activa del objeto. Así, el método run() debe implementarse de modo que cuando se recibe un mensaje de texto, se le coloque en el buffer. Recuerde que las operaciones sobre el buffer deben ser sincronizadas, de modo que se prevenga la corrupción de datos. La clase debe contar con un método storeifspace(), que almacene el mensaje si hay espacio en el buffer. También, con un método getline(), que retorna el mensaje de texto almacenado en el buffer. Si no hay mensajes, debe retornar un valor null. 3.6. La clase NetReader La clase NetReader debe simplificar laq lectura de datos desde el canal de comunicación que se obtiene de un socket. La cadena EOF se da como valor de retorno en el canal cuando un archivo termina o cuando se detecta un error. La razón común de un error es que el canal ha sido cerrado del otro lado, en cuyo caso retornar EOF resulta la acción apropiada. De tal modo, esta clase cuenta con un método getline() el cual lee una línea de caracteres del canal de comunicación, y cualquier error debe tratarse como un fin de archivo. También, debe contar con un método close() que cierre el canal de manera ordenada. 3.7. La clase NetWriter La clase NetWriter debe utilizarse para simplificar la escritura de datos a un canal que se obtiene mediante un socket. El constructor de esta clase toma como argumento al socket para crear un stream de salida. Requiere contener el método putline(), que escribe al canal de comunicación y el método close(), que cierra en canal en la máquina remota.
Referencias [] Ken Arnold and James Gosling. The Java Programming Language. Addison-Wesley, 996. [2] Barry Boone. Java Essentials for C and C++ Programmers. Addison- Wesley, 996. [3] Distributed Processes: A Concurrent Programming Concept. In Communications of the ACM 2(), 978, pp. 934-94. [4] Gary Cornell and Cay S. Horstsmann. Core Java. Prentice-Hall, 996. [5] David Flanagan. Java in a Nutshell. O Reilly, 996. 2