Pattern Oriented Software Architecture Forwarder-Receiver Jamir Antonio Avila Mojica Cesar Julio Bustacara Medina Agenda Introducción Patrón Forwarder-Receiver Ejemplo Contexto Problema Solución Estructura Dinámica Variantes Usos conocidos Introducción Comunicación. • Estos patrones ayudan a organizar la Comunicación entre componentes. • Solamente unos pocos sistemas de mediana y gran escala corren en un único computador, la mayoría de ellos usan redes de computadores. Introducción • Los sistemas distribuidos permiten compartir y utilizar recursos disponibles en la red. • Máquinas rápidas y costosas pueden alojar servicios centrales como sistemas de administración de bases de datos, mientras que máquinas más económicas pueden acceder a estos servicios de forma remota. • En las compañías el trabajo es inherentemente distribuido Introducción • Para que los sistemas distribuidos colaboren es necesario que se comuniquen unos con otros. Sin embargo, el problema es que hay muchos mecanismos de comunicación. • Hay que reducir el acoplamiento entre los componentes de un sistema distribuido y los mecanismos que usa para comunicarse. Dos aspectos claves son el encapsulamiento y la transparencia de ubicación. Introducción • El encapsulamiento de la comunicación facilita ocultar los detalles de comunicación a los usuarios. Normalmente mediante una interfaz de programación sobre las facilidades de comunicación de bajo nivel. • La transparencia de ubicación permite a las aplicaciones acceder a los componentes remotos sin conocer su ubicación física. Introducción Dos patrones abordan estos tópicos • Forwarder-Receiver. Proporciona comunicación entre procesos transparente para sistemas de software en un modelo de interacción compañero-compañero. • Client-Dispatcher-Server. Proporciona transparencia y oculta los detalles del establecimiento de la comunicación entre clientes y servidores. Patrón Forwarder-Receiver • Proporciona comunicación entre procesos transparente para sistemas de software en un modelo de interacción punto a punto. • Introduce forwarders y receivers para desacoplar los puntos de los mecanismos de comunicación. Ejemplo • Una compañía ofrece aplicaciones para la administración de redes de computadores. • Posee agentes responsables de observar y monitorear eventos y recursos Contexto • Comunicación punto a punto. Problema • Una forma común de construir aplicaciones distribuidas es usar los mecanismos de bajo nivel disponibles para comunicación entre procesos (IPC) como TCP/IP, sockets o colas de mensajes. • Proporcionados por casi todos los sistemas operativos, y son muy eficientes comparados con mecanismos de mayor nivel como las llamadas a procedimientos remotos. Problema • Sin embargo, estos mecanismos introducen dependencias en protocolos de red y sistemas operativos. • Usando un mecanismo específico, la solución resultante restringe la portabilidad, la capacidad del sistema de soportar entornos heterogéneos y hace difícil cambiar el mecanismo de IPC después. Problema • El patrón Forwarder-Receiver es útil cuando necesite balancear las siguientes fuerzas: – Debe permitir la intercambiabilidad de los mecanismos de comunicación. – La cooperación de componentes sigue un modelo punto a punto, en el que el emisor solamente necesita conocer los nombres de sus receptores. – La comunicación entre puntos no debe tener mayor impacto en el rendimiento. Solución • Peers distribuidos colaboran para resolver un problema particular. • Un peer puede actuar como: – Un cliente – Solicitar servicios – Un servidor – Proporcionar un servicio – Ambos (cliente y servidor) Solución • Los detalles del mecanismo IPC para enviar o recibir mensajes son ocultos encapsulando esta funcionalidad específica en componentes separados. • Ejemplos de esta funcionalidad son: – las transformaciones de nombres a ubicaciones físicas – el establecimiento de los canales de conexión – el marshaling / unmarshaling de mensajes. Estructura • Consiste de tres tipos de componentes: forwarders, receivers y peers: Estructura • Los componentes peers son responsables de tareas de aplicación. Para cumplir sus tareas requieren comunicación con otros peers. Estos pueden estar localizados en procesos diferentes, e incluso en una máquina diferente. Cada peer conoce los nombres de los peers remotos con los que necesita comunicarse. Estructura • Los componentes forwarder envían mensajes que atraviesan los límites del proceso. • Proporciona una interfaz general que es una abstracción de un mecanismo IPC particular, e incluya funcionalidad para hacer el marshal y entrega de mensajes. • Cuando un forwarder envía un mensaje a un peer remoto, determina la ubicación física del receptor usando su transformación nombre a dirección. Estructura • En el mensaje transmitido el forwarder especifica su nombre, para que el peer remoto pueda enviar la respuesta a quien originó el mensaje. Estructura • Los componentes receiver son responsables de recibir los mensajes. Un receiver ofrece una interfaz general que es también una abstracción de un mecanismo IPC particular. Incluye la funcionalidad para recibir y hacer el unmarshal de mensajes. Estructura - Funcionalidad • Envió de Mensajes: – Para enviar un mensaje a un peer remoto, el peer invoca el método sendMsg de su forwarder, pasando el mensaje como argumento. – El método sendMsg debe convertir los mensajes a un formato que entienda el mecanismo IPC seleccionado. Para ello, invoca marshal, y usa deliver para transmitir el mensaje de datos al receiver remoto. Estructura - Funcionalidad • Recepción de Mensajes: – Cuando el peer quiere recibir un mensaje de un peer remoto, invoca el método receiveMsg de su receiver, y el mensaje es retornado. – receiveMsg invoca receive, quien usa la funcionalidad del mecanismo IPC para recibir mensajes, luego llama unmarshal para convertir el mensaje a un formato que entienda el peer. Dinámica • El siguiente escenario ilustra un típico ejemplo del uso de la estructura Forwarder-Receiver. Dos peers P1 y P2 comunican entre sí. Para esto, P1 usa un forwarder Forw1 y un receiver Recv1. P2 maneja sus transferencias de mensajes con un forwarder Forw2 y un receiver Recv2: – P1 solicita un servicio del peer remoto P2. Para ello envía la solicitud a su forwarder Forw1 y especifica el nombre del receptor. – Forw1 determina la ubicación física del peer remoto y hace el marshal del mensaje. – Forw1 entrega el mensaje al receiver remoto Recv2. Dinámica – En algún momento anterior P2 ha solicitado a su Recv2 esperar solicitudes entrantes. Ahora, Recv2 recibe el mensaje que llega de Forw1. – Recv2 hace el unmarshal del mensaje y lo pasa a su peer P2. – Mientras tanto, P1 llama a su receptor Recv1 en espera de una respuesta. – P2 ejecuta el servicio solicitado, y envía el resultado y el nombre del receptor P1 al forwarder Forw2. El forwarder hace el marshal del resultado y lo entrega a Recv1. – Recv1 recibe la respuesta de P2, hace el unmarshal y lo entrega a P1. Dinámica Implementación • Para implementar el patrón de diseño ForwarderReceiver, itere los siguientes pasos: – Especifique una transformación nombre a dirección. Un nombre puede hacer referencia a un grupo de direcciones no necesariamente a una dirección única. Implementación – Especifique los protocolos de mensajes que van a ser usados entre peers y forwarders. Este protocolo define la estructura detallada del mensaje de datos que un forwarder recibe de su peer. Haga lo mismo para el protocolo de mensajes usados entre receivers y peers. El siguiente es un ejemplo de mensaje enviado entre peers y forwarders y viceversa: class Message { public String sender; public String data; public Message(String theSender, String rawData) { sender = theSender; data = rawData; } } Implementación • Seleccione un mecanismo de comunicación. La decisión se debe tomar de acuerdo con los mecanismos de comunicación disponibles en el sistema operativo. Considere también: – Es importante ser eficiente. Un mecanismo de bajo nivel puede ser muy eficiente y flexible en cuanto a los protocolos de comunicación que se pueden construir. – Los mecanismos de bajo nivel requieren gran esfuerzo de programación, y son dependientes de la plataforma que se utilice. • Para el ejemplo se seleccionó usar sockets. Implementación • Implemente el forwarder. Encapsule toda la funcionalidad para enviar mensajes fuera de los límites del proceso en el forwarder. El forwarder proporciona esta funcionalidad a través de su interfaz pública y encapsula los detalles de un mecanismo de IPC particular. Defina un almacén que transforme nombres a direcciones físicas. El forwarder lo accede para recuperar las direcciones físicas de los receptores antes de establecer el enlace al peer remoto. Este almacén puede ser dinámico, modificable con el tiempo, o estático. Decida si cada forwarder tiene su propio almacén o si hay uno compartido por todos. Implementación • En el ejemplo se usa la dirección IP acompañada por el número de socket: class Entry { private String destinationId; // máquina destino private int portNr; // número de puerto public Entry(String theDest, int thePort) { destinationId = theDest; portNr = thePort; } public String dest() { return destinationId; } public int port() { return portNr; } } class Registry { private Map<Entry> hTable = new Hashtable<Entry>(); public void put(String theKey, Entry theEntry) { hTable.put(theKey, theEntry); } public Entry get(String aKey) { return hTable.get(theKey); } } Implementación • El constructor de la clase Forwarder espera un argumento theName de tipo String que especifica el nombre lógico del peer. Cuando un peer invoca el método sendMsg ocurre lo siguiente: – El método sendMsg invoca el método marshal para convertir el mensaje a una secuencia de bytes. – El método deliver es invocado. Este método busca la dirección física del peer remoto en el almacén local. • Para ello, la clase global fr contiene un miembro fr.reg que es una instancia de Repository. • deliver abre un socket, se comunica con el peer remoto, transmite el mensaje y cierra los sockets. Implementación class Forwarder { private Socket s; private Outputstream oStr; private String myName; public Forwarder(String theNarne) { myName = theName; } private byte[] marshal (Message theMsg) { / * . . . */ } private void deliver(String theDest, byte[] data) { try { Entry entry = fr.reg.get(theDest); s = new Socket(entry.dest(), entry.port()); oStr = s.getOutputStream(); oStr.write(data); oStr.flush(); oStr.close(); s.close(); } catch (IOException e) { /* . . . */ } } public void sendMsg (String theDes t , Message theMsg) { deliver(theDest, marshal(theMsg)); } } Implementación • Implemente el receiver. Encapsule toda la funcionalidad para recibir mensajes en el receiver. Proporcione al receiver con una interfaz general que abstraiga los detalles de un mecanismo particular IPC. El receiver necesita incluir funcionalidad para recibir y unmarshaling los mensajes. Con el patrón Whole-part cada una de estas responsabilidades se puede descomponer en una parte separada del componente receiver. Implementación • Además, como los peers corren asincrónicamente, se debe decidir si los receivers deben bloquearse hasta que llegue un mensaje. – Si es así, el receiver espera un mensaje entrante. Solamente regresa el control a su peer cuando llegue el mensaje. Esto es apropiado cuando el peer dependa del mensaje entrante para continuar su tarea. – En los demás casos, se deben implementar receivers no bloqueantes que permite a los peers especificar valores de time-out. En caso de que no llegue un mensaje en el tiempo especificado, el receiver regresa una excepción a su peer. Implementación • Si el mecanismo de IPC no soporta I/O no bloqueante, debe usarse un hilo separado en el peer para manejar la comunicación. • El uso de más de un canal de comunicación con los receivers es otra decisión importante de diseño. Tales receivers son capaces de demultiplexar los canales de comunicación – esperan hasta que un mensaje llegue en uno de los canales y regresa el mensaje a su peer. • Como es posible que más de un mensaje llegue al mismo tiempo, los receiver pueden proporcionar una cola de mensajes interna para hacer el buffer de mensajes. El servicio del sistema select en UNIX permite esperar por eventos en un conjunto de descriptores de archivos y sockets. Implementación • En el ejemplo, si un peer instancia un receiver, llama al constructor y pasa su propio nombre como argumento. • El receiver usa este nombre para determinar que socket usar para la recepción del mensaje. Cuando un peer quiere recuperar un mensaje, llama al método receiveMsg del objeto Receiver, quien a su vez invoca el método receive. El método receive hace lo siguiente: – Después de recuperar el número del puerto del almacén, abre un server socket y espera las conexiones de los peers remotos. – Tan pronto se establece la conexión, el mensaje y su tamaño son leídos, receive retorna los datos a receiveMsg. • Finalmente, receiveMsg invoca unmarshal para convertir la secuencia de bytes en un objeto Message y regresa este objeto al peer. Implementación class Receiver { private ServerSocket srvS; private Socket s; private InputStream iStr; private String myName; public Receiver(String theName) { myName = theName; } private Message unmarshal(byte[] anArray) {/*...*/ } private byte[] receive() { int val; byte buffer[] = null; try { Entry entry = fr.reg.get(myName); srvS = new ServerSocket(entry.port(), 1000); s = srvS.acdept(); iStr = s.getInputStream(); val = iStr.accept(); buffer = new byte[val]; iStr.read(buffer); iStr.close(); s.close(); srvS.close(); } catch (IOException e) { /* . . . */ } return buffer; } public Message receiveMsg() { return unmarshal(receive()); } } Implementación • – Implemente los peers de la aplicación. – Particione los peers en dos conjuntos: clientes y servidores. – La intersección de ambos no necesariamente es vacía. – Si un peer actúa como cliente, envía un mensaje a un peer remoto y espera la respuesta. Después de que haya recibido la respuesta, continúa con su tarea. – Los peers actúan como servidores esperando contínuamente mensajes entrantes. Implementación • Cuando llegan los mensajes, ejecutan un servicio que depende del mensaje recibido y envían la respuesta al origen. • La comunicación entre los peers no siempre es de dos vías. Algunas veces es suficiente para un peer enviar un mensaje a otro sin requerir respuesta; hay peers que envían mensajes y continúan con su trabajo. Esta comunicación de una vía permite una comunicación asincrónica entre emisores y receptores. Implementación • A continuación hay un ejemplo de un peer actuando como servidor: class Server extends Thread { Receiver r; Forwarder f; public void run() { Message result = null; r = new Receiver("Server"); result = r.receiveMsg(); f = new Forwarder("Server"); Message msg = new Message("Server", "I'm alive"); f.sendMsg(result.sender, msg); } } Implementación • Implemente una configuración inicial. Cuando el sistema sea iniciado, forwarders y receivers deben contar con una transformación válida nombre a dirección. Introduzca una rutina separada de inicialización que crea un depósito e ingrese las parejas nombre / dirección. class Configuracion { public Configuracion() { Entry entry = new Entry(“127.0.0.1”, 1111); fr.reg.put(“Client”, entry); entry = new Entry(“127.0.0.1”, 2222); fr.reg.put(“Server”, entry); } } Variantes • Forwarder – Receiver sin transformación nombre a dirección. Algunas veces el rendimiento es más importante que ser capaz de encapsular todos los detalles del mecanismo IPC. Usos conocidos • El toolkit de desarrollo de software TASC soporta la implementación de estructuras ForwarderReceiver en aplicaciones distribuidas para sistemas de automatización de fábricas. • Los sistemas de switches ATM-P usan el patrón de diseño Forwarder-Receiver para implementar IPC entre los componentes distribuidos estáticamente. • También es usado para implementar comunicación entre procesos en el entorno distribuido de Smalltalk BrouHaHa Consecuencias • Ventajas – Comunicación eficiente entre procesos. El patrón facilita la elaboración de mecanismos de comunicación entre procesos muy eficientes. – Encapsulamiento de facilidades IPC. Todas las dependencias de IPC concretos son encapsuladas en los forwarders y receivers. • Desventajas – No soporta reconfiguración flexible de componentes. Los sistemas forwarder–receiver son difíciles de adaptar si la distribución de los peers cambia en tiempo de ejecución. Bibliografía • Pattern-Oriented Software Architecture: A System of Patterns, F. Buschmann, R. Meunier, H. Rohnert, P. Sommerlad, M. Stal. John Wiley & Sons, 1996 • Blackboard Architectures, JayDee Technology Ltd. John Hunt, 2002, Blackboard Systems, Blackboard Technology Group, Inc, Daniel D. Corkill
© Copyright 2024