Práctica 2: Java Remote Method Invocation (RMI) Aplicaciones Telemáticas II Introducción El objetivo de esta práctica es conocer un poco más sobre el paradigma de objetos remotos. La idea principal es poder, desde una máquina, utilizar métodos de objetos que se encuentran en otra máquina. El lenguaje orientado a objetos Java nos permite trabajar con objetos distribuidos a través de RMI. La idea es la misma del esquema cliente-servidor. Un servidor, el cual crea objetos permitiendo que estas referencias sean accesibles por un cliente, el cual puede invocar métodos de estos objetos. La Interfaz, define el protocolo del objeto remoto. Aquí se encuentra la información que el cliente debe saber, es decir, la información sobre los métodos implementados por el servidor, así como los parámetros y el tipo de retorno. Ejemplo: Al igual que en la práctica 1 construiremos un servidor que entregue la hora actual. Primero debemos definir la interfaz. import java.rmi.*; import java.util.date; public interface FechaInterface extends Remote public Date getdate() throws RemoteException; La interfaz debe hacer un import de java.rmi, extender de Remote y cada método debe hacer un throws RemoteException. El siguiente paso es implementar el servidor: 1
Figure 1: Esquema comunicación cliente servidor 2
import java.rmi.*; import java.rmi.server.*; import java.util.date; public class ServidorFecha extends UnicastRemoteObject implements FechaInterface // constructor de la clase public ServidorFecha() throws RemoteException super(); // metodo que entrega la hora actual public Date getdate() throws RemoteException System.out.println("llamada de un cliente); return new Date(); // main del servidor public static void main( String args[] ) try ServidorFecha servidor = new ServidorFecha (); Naming.rebind( "rmi://localhost/servidor_fecha", servidor ); System.out.println( "Servidor de Fecha..." ); catch ( Exception e ) System.out.println(e); El servidor posee un main que crea un objeto del tipo ServidorFecha. Ahora el cliente: 3
import java.rmi.*; import java.rmi.server.*; import java.util.date; public class ClienteFecha public static void main( String args[] ) try // crea un objeto FechaInterface FechaInterface fechaobj = (FechaInterface)Naming.lookup( "rmi://localhost/servidor_fecha"); Date fecha = fechaobj.getdate(); System.out.println( "Fecha del servidor: " + fecha ); catch ( Exception e ) System.out.println(e);; Hasta el momento el código generado no presenta nada distinto de una implementación local, excepto las librerías empleadas y las líneas: Naming.rebind( "rmi://localhost/servidor_fecha", servidor ); En la implementación del servidor, al ocupar el método rebind lo que hacemos es registrar el objeto servidor (nombre que se asigno a la instacia) en el servidor en la dirección rmi://localhost/servidor fecha. Este parámetro debe ser conocido por el cliente. Luego, la línea: Naming.lookup("rmi://localhost/servidor_fecha" ); Indica que se buscará el objeto en rmi://localhost/servidor fecha. En este caso lo que nosotros creamos es una instancia de la interfaz FechaInterface la cual puede invocar los métodos definidos en la implementación, en este caso, el método getdate(). Una vez que tenemos las clases implementadas debemos compilar usando javac. Al igual que la práctica 1 donde usábamos rpcgen para generar los ficheros que manejan la comunicación cliente servidor, java rmi nos permite generar estos ficheros. Para esto debemos ejecutar el comando rmic sobre la clase que implementa el servidor. En nuestro caso el comando sería: 4
rmic ServidorFecha Esto genera un fichero llamado ServidorFecha Stub.class el cual se encarga de la comunicación entre cliente y servidor. La clase stub es una clase con los mismos métodos que el objeto remoto pero incluye el procesamiento y envío de mensajes por red. La clase stub debe estar visible tanto por el cliente como por el servidor, por lo que debe estar en el servidor en algún lugar público o el cliente debe tener una copia del archivo. RMI Registry Una vez generados los objetos remotos, debemos registrarlos, para eso ejecutamos el comando rmiregistry: [prompt] rmiregistry p Este comando crea y ejecuta un registro de objetos remotos en el puerto p si p es omitido el puerto por defecto es 1099. Finalmente podemos ejecutar nuestro servidor y cliente: [prompt] java ServidorFecha [prompt] java ClienteFecha Ejercicio 1 Implemente y ejecute el servidor de fecha descrito anteriormente. Ejercicio 2 Implemente un servidor que calcule pequeñas estadísticas sobre frases. El servidor debe proveer de un objeto con las siguientes funciones: int getnumerovocales(string a) int getnumeroletras(string a) int getnumeropalabras(string a) int getnumeroconsonantes(string a) El cliente debe proveer el siguiente diálogo: 5
Ingrese una oracion:? _ oracion: ejemplo de oracion Elegir operacion: 1 numero de vocales 2 numero de letras 3 numero de palabras 4 numero de consonantes 0 Salir opcion? _1_ El numero de vocales es: 8 opcion? _3_ El numero de palabras es: 3... Entrega Debe entregar todos los ficheros generados, a través de la sección prácticas del aula global en un fichero comprimido, con el nombre NIA P2.zip, antes de las 24:00 del miércoles 30 de enero. Nota Para la resolución del ejercicio pueden ser útiles las siguientes funciones de la clase String. char charat(int i) Retorna el caracter en el indice i. int indexof(string str, int fromindex) Retorna la ubicación del String str a partir del índice f romindex. Para leer un string desde pantalla. BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); System.out.print("Ingrese una palabra"); String palabra = in.readline(); Esto escribe en pantalla Ingrese una palabra y luego guarda lo ingresado en la variable palabra. 6