Objetos distribuidos en Cocoa usando NSConnection y NSProxy

Cuando nuestros programas crecen lo suficiente, nos encontramos con situaciones donde tenemos varios hilos de ejecución o incluso diferentes procesos que se ejecutan de forma paralela en la misma o en diferente máquina. En estas situaciones, es habitual tener que comunicar estos diferentes módulos.

Una típica forma de comunicación es el uso de objetos “distribuidos”, desde los vetustos (y terroríficos :)) objetos CORBA, pasando por RMI de Java o Remoting de .NET, hasta los mas modernos WebServices, estos mecanismos han sido y son ampliamente utilizados.

Explicado de una forma muy simple, estos mecanismos permiten llamar a un método de una instancia de un objeto que no se esta ejecutando en el mismo entorno que el llamador. Ese entorno puede ser otro hilo, otro proceso u otra máquina.

Como era de esperar, Cocoa plantea su aproximación al uso de objetos distribuidos. Como hemos hablado anteriormente en el blog, el mecanismo de invocación de métodos en Objetive-c basado en mensajes, ayuda a entender y a enfocar de otra manera el funcionamiento de la invocación remota de métodos de objetos.

En un lenguaje como Java, cuando invocas a un método remoto, realmente estas invocando a un método que tiene que existir en una clase “local”. Esta clase “local” habitualmente es un Proxy que se autogenera estáticamente. El Proxy por su parte, transforma la llamada en una comunicación con el servidor remoto, que se encarga de invocar el método y devolver el retorno.

En Objetive-C, una llamada a un objeto remoto, se traduce en un mensaje que se “enruta” hasta llegar al objeto receptor. En este caso, el Proxy no es necesario autogenerarlo, pues como hablamos, el Proxy será un objeto que es capaz de recibir en tiempo de ejecución cualquier tipo de mensaje. No tenemos la necesidad de que el método realmente exista para poder compilar nuestro código.

Las clases que entran en juego son numerosas, y el funcionamiento completo tiene su “intríngulis”🙂, por lo que en este post nos centraremos en el aspecto mas práctico, es decir, poner un ejemplo de como funciona.

El código se divide en dos partes, por un lado esta el objeto que va e estar ejecutandose en modo “servidor” y por otro, el lado del cliente.

Hablando del servidor, vamos a tener un objeto de tipo “Calculadora” que va a tener un método “addNumber:with:”, que como dice su nombre, sumará dos números. A este objeto lo vamos a llamar de forma remota.

@protocol CalculatorProtocol
- (int) addNumber:(int) a with:(int)b;
@end

@interface Calculator : NSObject<CalculatorProtocol> {
}
@end

El protocolo, nos va a ayudar a que el proxy sepa que el método existe. Realmente esto no es estrictamente necesario, ya que el mensaje se enrutará de todas maneras hasta llegar a la clase Calculator, pero sin embargo es una buena ayuda de cara a la comprobación que el runtime hace para saber si la clase remota responde o no al mensaje.

Una vez que tenemos el objeto que queremos exportar, necesitamos publicarlo, o como se llama en la documentación: “Vending an Object”.

Para ello, vamos a hacer uso de la clase NSConnection

Calculator* calculator = [[Calculator alloc] init];
NSConnection* theConnection = [[[NSConnection alloc] init] autorelease];
[theConnection setRootObject:calculator];
[theConnection registerName:@"calculator"];

[[NSRunLoop currentRunLoop] run]; 
 // Solo si nuestra aplicación no lo ha hecho ya
 // En caso de una aplicación Cocoa, esto no es necesario

Con esas 5 lineas, nuestro Servidor ya estará escuchando peticiones, y el objeto estará listo para usarse desde otro entorno de ejecución, fácil, ¿no?.

La parte cliente, no es que sea mucho mas compleja😉

id theProxy;
theProxy = [[NSConnection rootProxyForConnectionWithRegisteredName:@"calculator" host:nil] retain];
[theProxy setProtocolForProxy:@protocol(CalculatorProtocol)];
NSLog(@"%d", [theProxy addNumber:5 with:3]);

Una vez mas el objeto NSConnection nos va a servir para obtener la conexión al objeto remoto. Usamos la misma cadena que se utilizó en el registro, y pasamos “nil” al parámetro host, ya que en este ejemplo, el servidor esta en la misma máquina.

Ambos fragmentos de código se ejecutan en procesos diferentes, y como se espera, el resultado del cliente es imprimir un 8 en la pantalla de logs.

Sin duda, el post no ataca toda la complejidad que hay detrás de los mecanismos, y las diferentes alternativas que existen de cara a la configuración de la conexión u otros aspectos que entran en juego, pero aún así se puede ver lo sencillo que es invocar un mensaje sobre un objeto que esta ejecutandose fuera de nuestro proceso.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: