Llamada a procedimientos remotos Tema 2: Programación en Red, RMI 1 Previo: Objetos e interfaces en JAVA Interface 1 Data { m1 m2 m3 implementation of methods main() public class Client { private Client() {} public static void main(String[] args) { Hello server = (Hello) new Server(); String response = server.sayHello(); System.out.println("response: " + response); } } JAVA Remote Method Invocation (I) RMI es una implementación orientada a objectos del paradigma de llamadas a procedimientos remotos. RMI es una implementación solo en JAVA. El objecto remoto provee metodos remotos que pueden ser invocados por programas clientes Un cliente invoca los metodos remotos de la misma manera que se invocan metodos en objectos locales. Object 2 Object 1 2 public interface Hello { String sayHello(); } remote object object public class Server implements Hello { public Server() {} public String sayHello() { return "Hello, world!"; } } remote interface Main Cliente RMI 3 { Data m1 m2 m3 implementation of methods Main Servidor RMI 4 JAVA Remote Method Invocation (II) Un cliente tiene que conocer este remote interface para poder utilizarlo (Un registro RMI permite localizarlo). En RMI un servidor exporta un remote object registrandolo en un servicio de registro. El objecto remoto implementa un remote interface, es una extensión del interface Java (=se comporta igual), Los parametros de entrada y salida de los metodos se transmiten serializados. Cliente RMI Una aplicacion para invocar el metodo de un objecto remoto tiene que: Localizar el objecto en un registro: Registry RMI remote interface { Cliente RMI Data m1 m2 m3 implementation of methods Servidor RMI 5 Servidor RMI Un servidor de objetos remotos: implementa el interface de metodos remoto, Crea y exporta objeto remoto, Registrar objetos en un registro RMI. import java.rmi.registry.Registry; import java.rmi.registry.LocateRegistry; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; public class Server implements Hello { public Server() {} public String sayHello() { return "Hello, world!"; } public static void main(String args[]) { try { Server obj = new Server(); Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0); client registro server Registry registry = LocateRegistry.getRegistry(); Registrar(objecto) registry.bind("Hello", stub); localizar(nombre) System.err.println("Server ready"); Ref. Objeto } catch (Exception e) { System.err.println("Server exception: " + e.toString()); Objecto.metodo() e.printStackTrace(); } } 7 } Se invoca el metodo en el objecto devuelto con una invocación normal. import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; public class Client { private Client() {} public static void main(String[] args) { String host = (args.length < 1) ? null : args[0]; try { Registry registry = LocateRegistry.getRegistry(host); Hello stub = (Hello) registry.lookup("Hello"); String response = stub.sayHello(); System.out.println("response: " + response); } catch (Exception e) { System.err.println("Client exception: " + e.toString()); e.printStackTrace(); } } } remote object object El objecto devuelto tiene que tener el cast del interface del objecto remoto, El objecto devuelto se “comporta” como el objeto remoto. client registro server Registrar(objecto) localizar(nombre) Ref. Objeto Objecto.metodo() 6 Interface Remote RMI Un interface remoto en RMI hereda de la clase Remote. Se comporta como cualquier interface en Java y cualquier clase puede implementarlo. import java.rmi.Remote; import java.rmi.RemoteException; public interface Hello extends Remote { String sayHello() throws RemoteException; } La excepción java.rmi.Remote debe ser listada con la sentencia throw en cada metodo del interface. Esta excepción salta cuando ocurren errores durante el procesamiento de la invocación de un método remoto, y dicha excepción debe ser recogida por el programa que efectua la invocación. Existen multiples causas que hacen saltar las excepciones: principalmente fallos de acceso o comunicación, o problemas en RMI como no encontrar los stubs, etc. 8 Architectura RMI Stubs y Skeletons en RMI STUB se comporta como un objeto local para el objecto cliente SKELETON llama al metodo correspondiente en el objeto remote Registry object client metodo(parametros) Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0); object server resultado El objeto stub se genera en el servidor, tiene la dirección IP y puerto del servidor codificada: Para que el cliente obtenga el Stub: Crea conexiones, crea mensajes de invocación remota, envia y recibe mensajes, se comunica con stub y skeleton. stub skeleton remote reference layer remote reference layer transport layer transport layer Se puede copiar manualmente el fichero (en Java 1.4) Se carga dinamicamente desde la direccion URL indicada por el registro RMI (anotada en el objeto a través de la propiedad java.rmi.server.codebase con la que se ejecuta el servidor) remote object Conexión Sockets, (u otros datagramas, multicast) object Registry RMI Remote interface logical data path { Cliente RMI physical data path object m1 m2 m3 Servidor RMI Stub.class 9 10 Servidor Ficheros / Web /.. Registro RMI Implementación del Servidor RMI client De manera transparente al programador: Cuando se arranca el servidor, comienza a escuchar en un puerto a la espera de peticiones de clientes. (puerto no fijo, el registro RMI dira al cliente cual es ese puerto). Los servidores deben de ser concurrentes, cada petición debe resolverse en un hilo. Multiples clientes pueden llamar concurrentemente al mismo procedimiento / objecto remoto, las implementaciones deben de tenerlo en cuenta. El cliente no crea objetos remotos (new de JAVA), para crear objetos remotos habria que utilizar un patrón factoria (ver http://java.sun.com/j2se/1.5.0/docs/guide/rmi/Factory.html ) 11 Los registros RMI son servidores que se pueden arrancar de dos maneras: Desde linea de comandos % rmiregistry <port number> Desde un programa servidor: registro server Registrar(objecto) localizar(nombre) Ref. Objeto Objecto.metodo() import java.rmi.registry.LocateRegistry; LocateRegistry.createRegistry (1099 ); La clase Naming provee metodos para acceder a un registro RMI y registrar objectos, localizar objectos, listar objectos o desregistrarlos. void bind (String name, Remote obj) El servidor registra un objeto con nombre name. void unbind (String name, Remote obj) Remote lookup(String name) El servidor desregistra un objecto. El cliente localiza un objecto por su nombre. Los nombres son del tipo: String registryURL = "rmi://localhost:" + portNum + "/someName"; 12 Otros Procedimientos Remotos En C: Interfaces Remotos (I) procedimientos remotos RPC,… Independientes de lenguaje: CORBA (orientado a objetos) Servicios Web, REST (basados en Web: XML….) Conceptos comunes: Remoto Registros Servidor Remoto Representacion Externa de Datos Data Marshalling Los programas locales necesitan saber como llamar a los procedimientos remotos (nombre de procedimiento, número y tipo de datos de parametros). Es necesario que los interfaces de los métodos remotos sean conocidos por los programas locales. Interface remote interface { Los interfaces se pueden definir de varias maneras, pej. como interfaces Java. Existen lenguajes de definición de interfaces IDL que permiten definir el interface de un procedimiento remoto independientemente del lenguaje de programación. Por lo tanto la implementación de un procedimiento remoto puede estar en un lenguage diferente al programa local: cliente en JAVA y servidor en C. implementation of methods 13 Interfaces Remotos (II) Method(para1,para2) Method2(param) Method3(param3) // file: SomeInterface.java import java.rmi.* public interface SomeInterface extends Remote { public String someMethod1( ) throws java.rmi.RemoteException; public int someMethod2( float ) throws java.rmi.RemoteException; // file Person.idl struct Person { string name; string place; long year; }; interface PersonList { readonly attribute string listname; void addPerson(in Person p) ; void getPerson(in string name, out Person p); long number(); }; 15 14 Procedimientos remotos vs. objetos distribuidos En lenguajes no orientados a objetos se implementan procedimientos remotos: las aplicaciones locales invocan procedimientos remotos. Ejemplo RPC. Los interfaces definen los procedimientos exportados. Existe un registro para localizar máquinas que proveean procedimientos remotos. Los clientes llaman a los procedimientos remotos como si fueran locales. En lenguajes orientados a objetos se implementa objectos distribuidos: los objetos locales invocan metodos de objectos remotos. Ejemplo RMI. Los interfaces definen las clases de los objectos que exportan metodos. Existe un registro para localizar los objectos remotos. Los clientes llaman a los metodos de los objectos remotos como si fueran locales. 16 Servidor de métodos remoto Registros El servidor implementa los procedimientos/objetos que se especifican en el interface. Por cada procedimiento/objeto precisa un skeleton. El servidor tiene que registrar los procedimientos/metodos en un registro: dinamicamente al iniciarse (RMI), o en archivo de configuración (RPC). De manera transparente al programador: Cuando se arranca el servidor, comienza a escuchar en un puerto a la espera de peticiones de clientes. Los servidores deben de ser concurrentes, cada petición debe resolverse en una proceso/hilo. Multiples clientes pueden llamar concurrentemente al mismo procedimiento / objecto remoto, las implementaciones deben de tenerlo en cuenta. 17 stub skeleton Remote Method Invoke Remote Method marshal parameters; send Request Unmarshal parameters; Invoke method execute code and return a value receive return value; marshal reply; send reply Unmarshall reply; return value receive return value client registro server Registrar(metodo) localizar(metodo) server, port, .. metodo() 18 Data marshalling Secuencia procedimientos remotos Local Method Los programas que necesitan invocar un procedimiento remoto, clientes, tienen que localizarlo a través de un registro (de igual manera que los clientes de Web utilizan el DNS para localizar servidores). Los programas que permiten ser invocados remotamente tienen que registrarse en un registro. El registro es un servicio independiente que mapea nombres de procedimientos u objetos con su implementación remota. 19 Los parametros de entrada y salida de un procedimiento remoto se deben de enviar en su totalidad (no es posible pasar referencias!!). Diferentes ordenadores pueden tener diferente representación interna para el mismo tipo de datos, por lo tanto una representación externa debe de ser acordada. Data marshalling es el proceso de (I) aplanar la estructura de datos, y (ii) convertir los datos a una representación externa. "This is a test." host A 1.2 marshalling 1. 2. 7.3 -1.5 Aplanar estructura datos Convertir a representación externa 110011 ... 10000100 ... RED 110011 ... 10000100 .. unmarshalling "This is a test." 1. Convertir datos a representación interna 2. Crear estructuras de datos -1.5 7.3 1.2 host B 20 Serialización Objetos JAVA (I) Representación Externa de Datos Binario vs. Ascii Representación externa de HTTP, TELNET “GET /index.html HTTP/1.0” Representación externa de ficheros en FTP 10101111000011111011010110 Para transmitir estructuras de datos complejas en procedimientos remotos se utilizan: XML (Extensible Markup Language): ascii Serialización JAVA: ascii Sun XDR, ASN.1 (Abstract Syntax Notation): binario XML es analogo a HTML. Pero las tags tienen significado. Ejemplo: <person id="123456789"> <name>Smith</name> <place>London</place> <year>1934</year> </person > Objetos JAVA se pueden aplanar en una estructura lineal que es adecuada para transmitirlos por la red, o para guardarlos en ficheros. Es necesario incluir información sobre la clase del objecto para que se pueda utilizar cuando se deserialice. Person p = new Person (“Smith”, “ London”, 1934); Explicación Valores serializados Persona Número de versión de 8-bytes 3 int año 1934 5 Pérez java.lang.String nombre: 6 Madrid a0 java.lang.String lugar: a1 Nombre clase, numero versión Número, tipo y nombre de las variables de instancia Valores de las variables de instancia 21 22 Serialización Objetos JAVA (II) •Para serializar una clase tiene que implementar el interface Serializable, que no tiene ningún método. •Los objetos serializables se pueden guardar en ficheros, o enviar por la red. •No todas las clases pueden serializarse, pej. Thread, Socket,… Procedimientos remotos vs. paso mensajes (sockets) // file: PersistentPerson.java import java..io.Serializable; public class PersistentPerson implements Serializable { ………………….. } Implementar con mensajes procedimientos remotos requeriria complejos mecanismos en servidor y clientes. Paradigma de procedimientos remotos intenta ocultar esa complejidad. Paradigma de procedimientos remotos facilita la programación de aplicaciones distribuidas ofreciendo API conocido. (pero, los sockets son más eficientes). PersistentPerson person = new PersistentPerson(); FileOutputStream os = new FileOutputStream(“tmp”); // OutputStream os = dataSocket.getOutputStream(); ObjectOutputStream out = new ObjectOutputStream(os); out.writeObject(person); out.close(); FileInputStream is = new FileInputStream(“tmp”); //InputStream is = mySocket.getInputStream(); ObjectInputStream in = new ObjectInputStream(is); PersistentPerson person = (PersistentPerson) in.readObject(); in.close(); 23 24