Sistemas distribuidos usando RMI

miércoles, 12 de diciembre de 2007
Los sistemas distribuidos se utilizan generalmente para distribuir carga en diferentes equipos. No es lo mismo que un cluster (existen varios tipos, cada uno con fines distintos), un cluster puede ser solo un caso de un sistema distribuido. En este contexto, uno puede, literalmente, dividir un sistema en partes que se pueden distribuir en distintas máquinas, máquinas reales o virtuales, o dentro de la misma máquina.

Pero y de qué sirve ? para qué dividir un sistema en varias partes ?. Las razones pueden ser variadas, pero seguramente todas tienen que ver con aumentar la velocidad de procesamiento, el agilizar la atención de clientes, disminuir la carga en el servidor principal, etc.

La idea general es que, por un lado se tienen clientes que esperan una atención y por otra un servidor que responde las peticiones, pero antes de responder, las peticiones se distribuyen a distintas máquinas de manera tal que cada una procesa una parte (o todo lo que pide un cliente) mientras que otro procesa otra parte (o a otro cliente). Esto impacta directamente en la velocidad de respuesta ya que no es un servidor el que se encarga de manejar todas las peticiones, sino que en realidad son varios.

Pero y cómo se desarrolla un sistema distribuido ? bueno, depende de la tecnología que utilizemos, pero en general es lo mismo. Un servidor implementa métodos que proveen servicios y se registran en el servidor como un servicio público el cuál puede ser accesado por los clientes.

Las tecnologías mas populares son Remoting de .NET y RMI de Java. También existe CORBA.

En esta instancia les quiero dar un ejemplo de RMI, mostrando los pasos o la "receta" a seguir. Hace un tiempo atrás, en este mismo blog, hice una guía de cómo hacer un sistema de pago online (nada real, solo virtual) al servicio de impuestos internos (SII) utilizando web services. Este ejemplo trata de lo mismo pero utilizando RMI en vez de web services. La base de datos la cambié de Derby a MySQL y el servidor de aplicaciones Glassfish no fue necesario.

En el link de RMI se explica cómo se utiliza pero la verdad para mi no fué tal cual sale explicado ahi, no se explica bien el tema del Stub que es parte escencial para generar un sistema distribuido con Java.

Lo primero que se debe hacer al momento de querer desarrollar un sistema distribuido (o cualquier tipo de sistema, despues de el desarrollo de requerimientos) es definir la arquitectura a utilizar. A continuación les mostraré un ejemplo de ésto:


Como se puede ver, al lado izquierdo se tienen dos clientes y al lado derecho un servidor. Este servidor posee una Interfaz que define los servicios a publicar y al lado se ve un Servicio Remoto, que en éste caso es una clase que implementa los métodos de la Interfaz.

La interfaz debe heredar de la clase Remote de java.rmi, mientras que la clase que implementa debe heredar de la clase UnicastRemoteObject de java.rmi.server.

A continuación se puede ver la interfaz InterfaceRemota:

package org.remoto;

import java.rmi.Remote;
import org.cliente.UsuarioBean;

/**
*
* @author metalklesk
*/
public interface InterfaceRemota extends Remote{

public String obtenerDeuda(String rut) throws java.rmi.RemoteException;

public String pagarDeuda(String rut, String monto) throws java.rmi.RemoteException;

public UsuarioBean obtenerUsuario(String rut) throws java.rmi.RemoteException;
}

y a continuación pueden ver la implementación de los métodos de la interfaz en la clase ServicioRemoto:

package org.remoto;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import org.cliente.UsuarioBean;
import org.logica.LogicaNegocio;

/**
*
* @author metalklesk
*/
public class ServicioRemoto extends UnicastRemoteObject implements InterfaceRemota{

private LogicaNegocio ln;

public ServicioRemoto() throws RemoteException{
ln = new LogicaNegocio();
}

public String obtenerDeuda(String rut) throws RemoteException {
String respuesta = ln.obtenerDeuda(rut);
return respuesta;
}

public String pagarDeuda(String rut, String monto) throws RemoteException {
String respuesta = ln.pagarDeuda(rut, monto);
return respuesta;
}

public UsuarioBean obtenerUsuario(String rut) throws RemoteException {
UsuarioBean usuario = ln.obtenerUsuario(rut);
return usuario;
}
}

La verdad, lo mas sano es separar en multicapas, de manera tal de que cuando se quiera modificar algo, solo afecte a la capa que corresponda siendo transparente para las demás en el sistema.

Lo siguiente es levantar el servicio, para ésto se necesita utilizar el método rebind de la clase Naming del package java.rmi. A continuación pueden ver el código de la clase Servicio que se encarga de ésto:

package org.principal;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.configuracion.AccesoConfiguracion;
import org.remoto.ServicioRemoto;

/**
*
* @author metalklesk
*/
public class Servicio {

private ServicioRemoto servicio;

public Servicio() {
try {
servicio = new ServicioRemoto();
} catch (RemoteException ex) {
Logger.getLogger(Servicio.class.getName()).log(Level.SEVERE, null, ex);
System.exit(1);
}
}

public boolean iniciarServicio(){
try {
Naming.rebind((AccesoConfiguracion.getInstance()).getServicioRMI(), servicio);
return true;
} catch (RemoteException ex) {
Logger.getLogger(Servicio.class.getName()).log(Level.SEVERE, null, ex);
return false;
} catch (MalformedURLException ex) {
Logger.getLogger(Servicio.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
}

public boolean pararServicio(){
try {
Naming.unbind((AccesoConfiguracion.getInstance()).getServicioRMI());
return true;
} catch (RemoteException ex) {
Logger.getLogger(Servicio.class.getName()).log(Level.SEVERE, null, ex);
return false;
} catch (NotBoundException ex) {
Logger.getLogger(Servicio.class.getName()).log(Level.SEVERE, null, ex);
return false;
} catch (MalformedURLException ex) {
Logger.getLogger(Servicio.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
}

@Override
public void finalize(){
pararServicio();
}
}

El método rebind recibe dos parámetros, un String con el nombre del servicio (puede ser cualquier cosa) y el objeto que implementa los métodos a publicar.

Ya con eso estamos casi listos por el lado del servidor. Lo siguiente es crear un Stub, que es un archivo .class que se encarga de entablar la comunicación en la red con el cliente. Este Stub se crea usando el comando rmic, en éste caso es:

rmic org.remoto.ServicioRemoto

lo cuál crea el archivo ServicioRemoto_Stub.class. Es importante decir que el comando anterior se hace con los archivos .class, no los .java, no se confundan con eso. Lo otro que es importante es que se fijen en los packages. No vale entrar a la carpeta org/remoto y ejecutar ahí el comando, se debe respetar el package.

Ahora debemos ejecutar:

rmiregistry

y el servicio rmi ya está registrado en el servidor, por default en el puerto 1099 (se puede cambiar pasando el puerto como parámetro al comando anterior).

Ahora solo resta crear el cliente. Lo importante por el lado del cliente son dos cosas.
Primero se debe tener la interfaz InterfaceRemota ya que es el puente de comunicación con el servidor y además se necesita el Stub (el mismo que se creó en el lado del cliente).

Para comunicarnos con el servidor se tiene el siguiente código:

package org.datos;

import org.cliente.*;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.configuracion.AccesoConfiguracion;
import org.remoto.InterfaceRemota;

/**
*
* @author metalklesk
*/
public class AccesoDatos {

private static AccesoDatos acceso = new AccesoDatos();
private static boolean instanciado = false;

private InterfaceRemota servicio;

public static synchronized AccesoDatos getInstance(){
if(!instanciado){
instanciado = true;
return acceso;
} else{
System.out.println("No se puede instanciar el acceso a datos mas de una vez");
return null;
}
}

public boolean conectar(){
try {
servicio = (InterfaceRemota)
Naming.lookup("rmi://" + (AccesoConfiguracion.getInstance()).getHost() + "/" + (AccesoConfiguracion.getInstance()).getService());
return true;

} catch (NotBoundException ex) {
Logger.getLogger(AccesoDatos.class.getName()).log(Level.SEVERE, null, ex);
return false;
} catch (MalformedURLException ex) {
Logger.getLogger(AccesoDatos.class.getName()).log(Level.SEVERE, null, ex);
return false;
} catch (RemoteException ex) {
Logger.getLogger(AccesoDatos.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
}

public String obtenerNombreUsuario(String rut){
if(servicio != null){
try {
UsuarioBean ub = servicio.obtenerUsuario(rut);
String nombreCompleto = ub.getNombre() + " " + ub.getApellidoPaterno() + " " + ub.getApellidoMaterno();

return nombreCompleto;
} catch (RemoteException ex) {
Logger.getLogger(AccesoDatos.class.getName()).log(Level.SEVERE, null, ex);
return null;
}

} else {
return null;
}
}

public String obtenerDeuda(String rut){
if(servicio != null){
try {
return servicio.obtenerDeuda(rut);
} catch (RemoteException ex) {
Logger.getLogger(AccesoDatos.class.getName()).log(Level.SEVERE, null, ex);
return null;
}

} else {
return null;
}
}

public String pagarDeuda(String rut, String monto){
if(servicio != null){
try {
return servicio.pagarDeuda(rut, monto);
} catch (RemoteException ex) {
Logger.getLogger(AccesoDatos.class.getName()).log(Level.SEVERE, null, ex);
return null;
}

} else {
return null;
}
}
}

Como pueden ver, para conectarnos utilizamos el método lookup de la clase Naming. Se recibe como parámetro, el host del servidor seguido del nombre del servicio.

Ya con ésto tenemos un objeto para instanciar los métodos remotos como si fuera de forma local.
El último paso importante es copiar el Stub al cliente. Recuerden que el Stub creado en el servidor pertenece al package org.remoto, el cuál, en el caso del servidor contiene 3 archivos .class (InterfazRemota, ServicioRemoto, ServicioRemoto_Stub) mientras que en el caso del cliente solo debe contener 2 (InterfazRemota, ServicioRemoto_Stub). No tiene ningún sentido que, en el cliente, exista ServicioRemoto.class ya que ésta clase implementa los métodos de la interfaz y utiliza recursos del servidor para proveer los servicios a los clientes.

De esa forma creamos un servicio con RMI en un servidor y creamos un cliente que consume ese servicio.

A continuación pueden ver el diagrama de clases del servidor:



y el diagrama de clases del cliente:



Qué ventajas existen ? aparte de las ya mencionadas (velocidad, agilidad, etc.) se tiene que es muchísimo mas rápido que web services. Sin embargo no es mejor que web services. Cada uno tiene su utilidad.

RMI sirve para desarrollar distemas distribuidos, pero solo de la misma tecnología RMI a java, Remoting a .NET, no permiten integración pero es rápido.


Web Services sirve para integrar sistemas distribuidos de distintas tecnologías, facilmente se pueden unir sistemas .NET con sistemas Java, pero es mas lento.


Acá les dejo unas capturas del sistema funcionando correctamente.



Como siempre, me pueden pedir el código dejándome sus correos y con gusto les enviaré el ejemplo de vuelta, es llegar y ejecutar. Además incluye el código fuente (desarrollado en NetBeans 6.0) y un informe sobre el trabajo.

saludos!!!!


EDITADO!!!

Subí el código a un servidor para que puedan hacer la descarga sin necesidad de enviarme sus correos (así no tienen que esperar a que yo lea el correo para rebotarlo a ustedes), si tienen problemas para la descarga seguimos con el método tradicional del correo electrónico.

Descarga

saludos !!!

116 comentarios:

faramos dijo...

Hola, te agradeceria mucho el codigo, faramos@gmail.com, gracias...

Anónimo dijo...

hola, seria de gran ayuda me envies el codigo, patuchotorres@hotmail.com, gracias.. suerte

Anónimo dijo...

Hola Daniel,este tema es muy interesante.Te agradeceria que ke me enviaras el codigo a vinfantesgil@hotmail.com...Gracias

Juliet dijo...

como esta ud.,estoy haciendo un trabajo de RMI, no sé si pueda compartirme su código, muchas gracias de cualquier forma. jubabuc@yahoo.es

xuli dijo...

hola,
gran trabajo con los diagramas.
Me gustaría recibir el código para hacer comparaciones de resultados, te agradecería que me lo enviases.
saludos y gracias, jmmeira@gmail.com

Anónimo dijo...

Hola me interesa el tema, podria enviarme el codigo de su trabajo a ymatias@estudiantes.uci.cu , le ha quedado muy bien la explicacion...Gracias.

Anónimo dijo...

Hola David!
Gracias por el excelente trabajo que ha realizado, el tema me interesa muchísimo y lo que ha publicado me ha sido de gran ayuda, no obstante si pudiera mandar el código se lo agradecería de veras.
laura.lusalane@gmail.com
Gracias, un saludo!

Anónimo dijo...

hola, buenos articulos muy practicos, espero que me puedas mandar el codigo mi correo es lestat_nm@yahoo.com.mx y tambien si tienes el de webservices que publicaste ya que el link me aparece roto, aunque pude hacer algunas cosas con las pantallas me gustaria ver todo tu codigo, gracias

Anónimo dijo...

hola, estoy realizando un trabajo con rmi y agradeceria que pudiera enviarme su codigo, mi correo es: solrac.azathot@gmail.com... de antemano gracias.

Anónimo dijo...

Hola Daniel, estoy realizando un trabajo en el cual tengo que aplicar Rmi. Te agradeceria me enviaras el código de tu publicación. Desde ya michas Gracias.
monica73@hotmail.com

Anónimo dijo...

excelente trabajo me podrias facilitar el codigo mi correo es
bolo_rubio@hotmail.com

Anónimo dijo...

Hola Daniel, me gustaria que me facilitaras el codigo como lo explicas aqui, mi correo ceibosnet@gmail.com
De antemano muy agradecido

david dijo...

Que tal, yo tambien estoy interesado en el código, lo agradeceria mucho
fdcamaya@gmail.com

Anónimo dijo...

hola que tal, me parece muy buen trabajo, y me gustaría hecharle un vistazo a tu código, de antemano muchas gracias, enrique.ifg@gmail.com, hasta pronto...

Daniel G. dijo...

Hola, los diagramas estan perfectos, por favor me envias el codigo:
guiafar@gmail.com

Anónimo dijo...

Hola, te agradecería mucho si pudieras enviarme el código azarthe@hotmail.com, muchísimas gracias...

Sebastian dijo...

Hola Daniel me ayudarias mucho enviandome el codigo gracias, valdisebas8@gmail.com, gracias..

Anónimo dijo...

Hola, te agradecería mucho si pudieras enviarme el código conmile@etb.net.co, muchísimas gracias...

h4ckf!sh dijo...

HOLA.

Excelente trabajo.

Necesito urgentemente implementar una aplicación haciendo uso de RMI con Netbeans 6.0.

Creo que tu ejemplo puede ser un buen punto de partida.

Este es mi correo: infvca00@estudiantes.unileon.es

Te agradecería cualquier ayuda.

Anónimo dijo...

hola me gustaria saber si me podrias enviar el programa que desarrollastes ne netbeans 6.0, el de sistemas remotos, es decir el de RMI..... gracias por tu atencion.... mi mail es like_preciosa@hotmail.com; jesuspererav@hotmail.com; mil gracias.....

Vitor dijo...

Tengo que realizar un proyecto en RMI y Netbeans 6, les agradeceria q me enviaran el codigo de este ejemplo como punto de partida y pues compartir info con aquellos q se encuentran en la misma situacion q yo

vitorcardona@gmail.com

Gracias

Francia dijo...

Hola, me interesa mucho el tema que has desarrollado y necesito aprender. Agradeceria que me enviaras el codigo, a fran_pazmania@hotmail.com.
De antemano muchas gracias

Anónimo dijo...

Buenos dias... buenisimo ese codigo.. mi pregunta es como puedo hacer un chat con rmi o algo similar para una red local que necesito tener distribuida?? mi mail es jf_max@hotmail.com te agradezco si me puedes decir si me puedes colaborar o en donde lo puedo buscar ya que vos sabes de eso.. mil gracias..

Rafael dijo...

Hola me intesa el codigo del chat
muchas gracias por tu colaboracion

Daniel Morales Salas dijo...

rafael, cual es tu correo ?

Ramon dijo...

Hola, este tema es muy interesante y me gustaria seguir aprendiendo serias tan amable de pasarme el codigo felicitaciones por tu trabajo, mi correo es ramon.gamez@gmail.com

Saludos!!!

Roberto dijo...

Hola, un saludo y felicidades por tu trabajo! muy valioso y de gran apoyo para muchos que estamos aprendiendo sobre RMI. Te agradecería si por favor me pudieras compartir tu trabajo (codido fuente y Proyecto Netbeans, así como su documentación).
mi correo es rlimon@itson.mx o therobert_xd@hotmail.com

Muchas gracias por tu apoyo!

Macabro dijo...

Estimado, muy buen aporte de RMI, podrías facilitarme el código a la siguiente dirección: sb.and.fc@gmail.com
De antemano, muchas gracias.

Saludos.

Anónimo dijo...

eyy muy buen trabajo,,, te agradeceria si puedes facilitarme el codigo ... email: carcass1982@gmail.com

Gracias

Anónimo dijo...

Hola! esta muy bueno te agadeceria que me enviaras el codigo a rdl1515@gmail.com o a mcstivi_55@yahoo.es

Anónimo dijo...

Hola! esta muy bueno! Agradeceria que me enviaras el codigo a rdl1515@gmail.com

Anónimo dijo...

Es muy interesante por favor mandame el codigo a joseto@uigv.edu.pe

Daniel Morales Salas dijo...

al último amigo ...

te envié el código y todo pero me rebotó el correo ya que el tamaño es mas grande de lo que el servidor de tu correo permite. Lo mejor es que me des una cuenta de gmail y así te llegará sin problemas.

saludos !!

Anónimo dijo...

Hola, te agradecria mucho el codigo sacmem@yahoo.com.mx, y si me puedieras resolver algunas dudas que me quedaron te lo agradeceria ,mucho, gracias

Patricio Sebastián dijo...

Hola!!

Soy estudiante, pero necesito hacer una aplicacion de esritorio, que permita el traspaso de mensajes, algo parecido a un messenger. La pregunta es: "¿Como utilizo RMI para realizar una apliacion de escritorio. ?"Algún tutorial al respecto.
Te felicito por el trabajo anterior, espermo me puedas ayudar. Te adjunto mi correo pcastro.torres@gmail.com
De antemano, gracias

Daniel Morales Salas dijo...

Lo que te conviene es desarrollar una "Enterprise Application" que consta de dos partes, un servidor y un cliente.

El "Enterprise Application Server" se monta sobre un servidor de aplicaciones (glassfish por ejemplo) y provee de servicios RMI (entre otros).

El Enterprise Application Client corresponde a una aplicación de escritorio que se conecta al servidor mediante RMI.

La gracia es que no debes crear ningún stub a mano, el IDE NetBeans lo hace todo por ti.

Eso, yo creo que lo mejor, en tu caso, seria usar ese tipo de aplicación.

saludos !!

Anónimo dijo...

Me harías un gran fabor si me lo pudieras hacer llegar a alejandro@miconslt.co.cu

ADRIANA dijo...

Me gustaria obtener el codigo, y adicionalmente me gustaria me indicara si un programa servidor escrito en C++ proporciona un objeto burbuja y se pretenden que accedan clientes de un lenguaje diferente como java, que problemas a nivel de heterogeneidad se podrian presentar, si se pretende que un objeto cliente invoque el metodo sobre el objeto servidor? mi email es: adrianacruzort@gmail.com

Daniel Dario Morales Salas dijo...

Adriana:

La única forma de que puedas llamar un servicio desde un cliente a un servidor es utilizar la misma tecnología en ambos lados o utilizar un mecanismo estándar de comunicación, no conozco otra forma.

Cuando expones un servicio RMI solo puedes comunicar aplicaciones java por el lado cliente y servidor, .NET, c, c++ u otros no tienen nada que hacer ahí, no tienen forma de consumir los servicios del servidor.

Lo mismo con Remoting, ahi no hay manera de que con java puedas consumir servicios con tecnología Remoting.

Distinto es el caso de Web Services, que justamente es una forma de integrar plataformas tecnológicas distintas (java, .NET, no se otras).

Una forma que podría usarse es mas a bajo nivel con sockets, un socket c puede comunicarse con un socket java, pero se debe utilizar un mecanismo estándar de comunicación, por ejemplo mediante mensajes de texto previamente definidos para que ambos se escriban y lean sin problema, o enviándose archivos XML como se hace con web services, eso es factible, se puede hacer.

Como ves, los problemas que puedan surgir dependen de como expones el servicio y que mecanismo provees para que los clientes se puedan conectar y consumir.

No se si mi respuesta te sirve, agradeceré tu comentario al respecto.

saludos !!

Daniel Dario Morales Salas dijo...

Un ejemplo de lo anterior es MSN, el sistema de mensajería instantánea de Microsoft. Mediante un protocolo de comunicación definido existen muchos clientes hechos en distintos lenguajes, por ejemplo:

Pidgin -> GTK
Emesene -> Python
Mercury -> Java
Amsn -> tl/tk
Kopete -> QT

y asi hay unos que incluso están en NCurses y funcionan desde consola.

Como ves, clientes hechos en distintos lenguajes se comunican entre si a través de un protocolo definido, seguramente la red msn utiliza sockets y paso de mensajes con alguna estructura definida, no me he puesto a averiguar pero me imagino que asi debe ser. Incluso hay clientes web, creo que tambien se levantan web services (en el servidor MSN).

saludos !!

Jacquie dijo...

Hola, si no es mucha molestia. Le agradecería que me envies el codigo de este ejemplo gracias =)
jackysanabria@yahoo.com o
jackysanabria@gmail.com

cristhian dijo...

Hola, mi nombre es cristhian de bolivia, antes q nada felicitarte por tu blog que es muy bueno, desearte q continues adelante, he intentado descargar tu ejemplo y siempre se cuerta, espero si no es mucha molestia que me mandaras tu ejemplo a mi correo cristhianchm@gmail.com ...
Esperando tu pronta respuesta me despido y muchas gracias

Anónimo dijo...

Hola,
pues buscando ejemplos de rmi me encontre con tu pag

seria mucha molestia que me mandaras el codigo completo porfavor mi correo es

yrak_07@ingenieros.com
yrak_07@yahoo.com.mx

me seria de gran ayuda

Anónimo dijo...

Hola, soy Lucas y estoy haciendo mi tesis usando RMI en mi sistema.
Pero ahora quiero implementar un Observer, es decir, que cuando el servidor me haga cambios en la base de datos(o donde sea), es decir que hubo algun otro cliente q me cambio de estado el sistema, quiero que este cambio sea comunicado a todos los clientes logueados al servidor. Mi problema es que cuando publico el metodo del cliente al rmi (este metodo es el que me inicia el proceso de actualizacion de datos en el cliente) me tira una excepcion:

java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
java.lang.ClassNotFoundException: cliente.LoginCliente_Stub
at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:352)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:207)
at sun.rmi.transport.Transport$1.run(Transport.java:148)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:144)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:460)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:701)
at java.lang.Thread.run(Thread.java:536)
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:247)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:223)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:350)
at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
at java.rmi.Naming.rebind(Naming.java:160)
at cliente.ConexionClientes.conectarCliente(ConexionClientes.java:135)

...
...

Mi pregunta es, si es que se puede hacer que el cliente tambien publique metodos para q el servidor los invoque. Porque por ahi pense q puede haber algun conflicto o algo y por eso surge la excepcion, debido a q ya revise todo y no hay forma de dar con el error.
Personalmente pienso q se deberia poder hacer tranquilamente..

Si alguno sabe, porfavor haganmelo saber...saludos y gracias

Daniel Dario Morales Salas dijo...

Hola.

Me parece que lo que quieres hacer en principio no se puede.

La única forma seria que el cliente fuera además un servidor, de manera tal que pueda registrar servicios y exponerlos a través de RMI. Esto significaría que el cliente debe tener el puerto de RMI abierto en el firewall (al igual que el servidor, totoal el cliente SERIA un servidor). El servidor debe conocer el IP del cliente y cada vez que quiera enviar los avisos que quieres, debe establecer la comunicación con cada cliente.

Ahora, no se si eso se pueda hacer, por el tema del STUB y eso. Tal vez si se pueda hacer ya que la última versión de java ya no requiere de un stub para establecer la comunicación.

Tal vez lo que quieres hacer queda mejor usando sockets y no RMI. En ese caso montas un servidor con ServerSocket y para cada cliente creas un Thread que maneje la entrada y la salida desde y hacia el cliente en particular, eso si que se puede, lo he hecho varias veces.

En ambos casos requieres abrir el puerto en el firewall del cliente y del servidor para poder establecer la comunicación de entrada.

saludos !!

Daniel Dario Morales Salas dijo...

Hola.

Buscando encontré en un FAQ sobre RMI de SUN la respuesta al implementar Observer y Observable con RMI, la dirección es la siguiente:

http://java.sun.com/j2se/1.4.2/docs/guide/rmi/faq.html#observer

saludos !!!!

viktor dijo...

me podrias enviar el codigo, te lo agradeceria mucho,ciberhot95@gmail.com , gracias

Anónimo dijo...

Hola! soy Lucas nuevamente

Primero quiero agradecerte Daniel por responder a mi inquietud.. y a pesar de que habia solucionado mi problema antes de leer el blogg, tu idea de como poder implementarlo, me sirve mucho para seguir aprendiendo.

En la siguiente pagina encontre los pasos para hacer mas o menos lo q yo queria hacer.
http://www.ryerson.ca/~dgrimsha/courses/cps841/RMICallbacks.html

Basicamente, lo que hice es crearme una clase en el cliente(CallbackClient) q extienda de UnicastRemoteObject e implemente una interface (q extiende Remote) y q dicha clase me provea de los metodos necesarios para q el servidor me notifique. Basicamente, tengo un solo metodo, el cual toma un numero como identificacion del cambio realizado en el servidor.

Ahora bien, cuando creo cada cliente, obtengo el servidor remoto, e invoco un metodo para registrame, al cual le paso la clase CallbackClient.

El servidor tiene un vector con todos los clientes "logueados" a él (CallbackClient). Entonces cuando dicho servidor detecta un cambio, lo q hace es notificar a los clientesRemotos q estan logueados, es decir, aquellos q esten en el vector.

MAs o menos esa es la solucion. Para mas detalles leer la pagina q deje mas arriba..

Espero q se entienda...

Saludos y muchas gracias por contestar a mi pregunta (perdon por no responder antes)

Susana dijo...

Hola esta muy padre tu programa.

Una pregunta hacerca de la bd. Me podrias un ejemplo de como de ser el campo rut porque a la hora que quiero entrar me dice que el rut es incorrecto por lo que no puedo entrar.

Te lo agradeceria mucho.

Daniel Dario Morales Salas dijo...

Hola

el rut es un numero de identificación único en Chile para cada persona que nace aquí.

El mio es 15371433-9, ingresa ese a mano en la base de datos (junto a los demás datos) y luego ingresa al sistema usando ese rut.

saludos !!!

Susana dijo...

MUCHAS GRACIAS
AMIGO

LO VOY A PROBAR

TE LO AGRADESCO

Susana dijo...

Hola

Otra pregunta acerca de tu programa distribuido con RMI.

Con la ruta ya no tuve ningun problema, muchas gracias, pero ahora me marca que no es posible encontrar el objeto remoto. A que se debe y como lo puedo solucionar.

Si me puedes volver a ayudar te lo agradeceria mucho

Daniel Dario Morales Salas dijo...

Ejecutaste la aplicación servidor ? registraste el servicio de la aplicación servidor con el comando rmiregistry ?

El comando rmiregistry se hace en el path de la aplicación.

Teniendo el servidor arriba y registrado no deberías tener problemas desde el cliente.

Una actualización al tutorial. Si usas la última versión de java ya no es necesario crear el stub a mano, se hace automático así que de ese paso todos se pueden olvidar.

saludos !!

TESE PLUS dijo...

hola te agradeceria que me enviaras el programa, ya que de un ejemplo de este tipo depende mi califiacion, espero me lo puedas hacer llegar. mi coreeo es thelove_is_magic@hotmail.com

Anónimo dijo...

Porfavor... por favor... podrias enviarme el codigo, no puedo descargarlo, necesito hacer una aplicacion en Java RMI y se que tu ejemplo me ayudaria un monton... please !!!

carlos_22bf@hotmail.com

Anónimo dijo...

Hola gracias por esta implementacion, te comento que estoy teniendo un problema, la cuestion es que estoy expandiendo un poco la aplicacion, pero cada vez que le cambio aunque sea el nombre a una variable desde el lado del servidor me sale un excepcion:
28/04/2009 07:46:50 PM org.datos.AccesoDatos obtenerNombreUsuario
GRAVE: null
java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
java.io.InvalidClassException: org.cliente.UsuarioBean; local class incompatible: stream classdesc serialVersionUID = 3865026427162206400, local class serialVersionUID = -8132005101180811284
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:173)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:178)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:132)
at $Proxy5.obtenerUsuario(Unknown Source)...

y cuando vuelvo a cambiar el nombre de la variable todo sale bien, la cuestion es que necesito expandir la clase usuariobean, para capturar mas datos de la base de datos, pero apenas cambio algo me sale la excepecion que puse arriba.

Nota: uso netbeans 6.5 en ubuntu 8.10, espero tu pronta ayuda, es para entregar mañana!!!, llevo dias intentando arreglar esto y no he podido, mi correo es kolshemayim@gmail.com

Daniel Dario Morales Salas dijo...

Estimado Anónimo ...

Si cambias en el lado servidor algún atributo o método de UsuarioBean, DEBES cambiarlo también en el lado cliente, si no lo haces te ocurre el problema que describes. Además de cambiar eso, debes bajar y subir de nuevo el servicio con el rmiregistry después de recompilar cliente y servidor. El tema va por que a través de RMI estas compartiendo un objeto de tipo UsuarioBean que debe ser igual en el lado cliente y servidor.

Saludos!

Anónimo dijo...

Uffff gracias gracias, ya me haz ayudado 2 veces, con el web service y aca, muchas gracias....eso solucionó mi problema

Anónimo dijo...

yo tambien desearia que me enviases el codigo de ser posible pues lo necesito para una tarea mi correo es ronsarmont@hotmail.com

Anónimo dijo...

Hola , excelente ejemplo de RMI, por favor me puedes enviar el código a vidalcq2607@gmail.com . Gracias

Anónimo dijo...

Roberto Almanza

Tu ejemple es muy bueno, por fa me lo puedes enviar al correo roberto_dmontre@hotmial.com
El link de descarga que tienes arriba no funciona?
gracias por todo

Anónimo dijo...

Hola

Muchas gracias por tu codigo, pero tengo problemas al ejecutarlo obtengo este mensaje: "no puede obtener el objeto remoto", como soy nuevo lei y dice que se tiene que subir el servicio, como hago esta parte? uso netbeans 6.5.1 y tengo java version 1.6.0_13.
Gracias

Daniel Dario Morales Salas dijo...

con rmiregistry

saludos!

Anónimo dijo...

Hola:

Me puedes explicar el procedimiento para subir el servicio con rmiregistry. se que es por linea de comando pero debo estar en alguna carpeta especial del ServidorRMI-src?

Muchas gracias

Carlos

Daniel Dario Morales Salas dijo...

Estimado

Hay dos opciones en el archivo comprimido que te envie. Ir directamente a la carpeta binarios o a la carpeta src.

Si vas a la carpeta binarios/ServidorRMI, justo en esa posición ejecutas rmiregistry.

Si vas a src/ServidorRMI-src debes entrar además en build/classes, es decir, src/ServidorRMI-src/build/classes y ahi ejecutas rmiregistry.

Siempre que ejecutes una aplicación con RMI debes ejecutar el rmiregistry en el home de tu aplicación.

Saludos!

Guillermo C dijo...

Hola, me gustaría tener el codigo, estoy haciendo una tienda virtual con RMI para la universidad y no se si lo estoy haciendo bien o no, creo que con tu código podría sacarlo.
taho17@gmail.com
Muchas Gracias

Anónimo dijo...

muy interesante pero te agradeceria si me pasaras el codigo israel_tuquerrez@hotmail.com

Anónimo dijo...

hola, tengo yo estoy intentando saber de rmi en linux, espero que me puedas enviar tu prog..
gracias.. wsolorzanni@hotmail.com

Anónimo dijo...

hola, tambieén necesito el codigo por favor puedes enviarmelo a mi correo gasglarin@hotmail.com o saber como implementarlo desde netbeans

Anónimo dijo...

Daniel te agradeceria mucho si me pudieras enviar tu codigo
y tambien necesito implementar un sistema con rmi en netbeans 6.7 a mi correo ing_plascencia@yayoo.com.mx de ya muchas gracias.

Wilson Asher Dilse dijo...

hola, me llamo Wils,, estoy comensando a hacer un sistema distribuido,pero no se tando de eso,, vi su trabajo,, esta padrisimo, no se si me podrias envirme a mi correo, le estare por siempre agadecido mi E-mail es: wson_he@hotmail.com -_-

Anónimo dijo...

Hola muy buenisimo me puedes enviar el codigo por favor...
ozz_chelo@hotmail.com

Anónimo dijo...

Hola te agradeceria mucho el codigo, pero sobre todo estoy buscando los comandos que he de ejecutar en Netbeans para poder poner en marcha RMI
apuerta333@gmail.com

jacksharry dijo...

Hola te estare muy agradecido si compartes el codigo mi correo es vallaromejaha@hotmail.com

Anónimo dijo...

Hola que tal, estoy en un proyecto con RRMI, pero la cosa es que me sale un error unmarshall return, lo que pasa es que soy nuevo en el tema y no se porque razones podria darse este error de conexion, porfavor puedes enviarme una respuesta a este correo: sjb_edrm2003@hotmail.com te lo agradecere infinitamente, gracias...

COORDINACION dijo...

Hola, me ha parecido muy importante tu post, si es posible que me ayudes con el código mi correo es argenis.riofrio@gmail.com..

Te agradesco por tu ayuda

Anónimo dijo...

Hola, si me puedes mandar el código estaría muy agradecido
qliphoth-@hotmail.com

flow_72@hotmail.com dijo...

cual es el rut para ingresa??? por favor ayuden

Daniel Dario Morales Salas dijo...

No me acuerdo si incluí el mio o debes ingresar uno TU en la base de datos y usar ese, como sea te doy el mio: 15371433-9

saludos !

Anónimo dijo...

Hola Daniel estuve leyendo tu post y esta genial, serias tan amable de compartirme el proyecto en netbeans. te agradesco bastante.e-mail: ventura.jos3@gmail.com
pd. los link de usuarios.lycos no estan funcionando

Ivan dijo...

Hola Daniel el post esta de lo mas interesante justo estoy entrando a sistemas distribuidos en la universidad no se si me podrias enviar el codigo el link que dejaste dejo de funcionar mi correo es : ieperezm2@gmail.com

Cristian dijo...

Hola me intereso mucho tu publicación, muy interesante. si me lo puede al correo te lo agradecería mucho que tengo problemas al descargarlo gracias. saludos

aridios@hotmail.com

Anónimo dijo...

Hola me podrias mandar el sistema por favor!!

octavio_ar21@hotmail.com

desde ya muchas gracias

Anónimo dijo...

hola cordial saludo espero que me envies el codigo, gracias por tu aporte fabio.parra15@hotmail.com

Anónimo dijo...

Hola Daniel excelente tus aportes .. quiero preguntarte algo ... resulta que me pidieron hacer un sistema pos de pago con varios puntos de pago y no tengo claro si es bueno utilizar rmi o jsp.. tu que me aconsejas ... ademas si tienes alguna ayuda (codigo)para orientarme te lo agradezco ... de antemano mis agradecimiento y porfa .. regalame tus codigos mi correo es felipeuribe2002@yahoo.com

Anónimo dijo...

hola amigo......

sabes me parece muy interesante tu progama espuesto y necesito ejecutarlo me justaria ver la posibilidad que me envies el problema rmi resuelto con las carpetas y sub carpetas ya que se me ha hecho imposible compilar.....

soy de chile iquique..... frdmra197@hotmail.com

esperando respuesta atte. fredy

fredy m dijo...

buenas tardes a todos.....

necesito orientacion respecto a la creacion de los archivos stub por que ya todo lo que he leido me exican que las versiones superiores a java 1.5 ya se crean por automatico y ya no es necesario crearlos por consola...... ademas con respecto a este proyecto lo de copiado y todo pero no corre por que me avisa que falta el import org.configuracion.AccesoConfiguracion;
y falta import org.cliente.UsuarioBean, import org.logica.LogicaNegocio.... no cacho na.... bueno debe ser por que recien estoy en segundo semestre ing eje info... sera de gran ayuda poder recibir algun tipo de recomendacion

ette. fredy

Anónimo dijo...

ola soy thomas exelente tus aportaciones daniel oie podrias ayudarme con un peqeño proyecto???

solo q necesito es una concexion con una base de datos distribuida utilizando RMI la interfaz debe manipular la base de datos como borrar modificar o añadir algun dato como ves es algo sencillo podrias ayudarme

frepieful dijo...

YO TAMBIEN QUisiera q me envies el codigo a mi correo: freicia_07@hotmail.com

pirataxa dijo...

q tal Thomas, ayudame con el codigo xfa, te agradezco mucho
pirataxa@hotmail.com

Anónimo dijo...

Hola Daniel!Me gustaría que echaras un vistazo a este error, llevo ya varios días intentando solucionarlo pero no encuentro la causa.¿Qué puede estar pasando?

SERVIDOR: Excepcion-> java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
java.lang.ClassNotFoundException: AGENCIA.InterfazMetodosRemotos

Muchas Gracias!
PD: si puedes mándame tu código para que analice que hago mal(tonia_fcb@hotmail.com).

Un saludo, Toñi

Anónimo dijo...

Buen dia Daniel me podrias por favor facilitar el codigo de esta maravillosa aplicacion mi correo es juangonza27@hotmail.com

Anónimo dijo...

Daniel Excelente Aporte Podrias Orientarme en un trabajo que tengo ... necesito realizar un conexioon 3 bases de datos que contengan la misma informacion donde cualquier modificacion de alguna se repliquen los cambios en la otra pero que la informacion sea invocada atraves de java rmi , mi correo es shadowx6@hotmail.com

Anónimo dijo...

muy bueno tu block. un favor me podrias enviar el codigo para revisarlo mas a detalle. te agradesco de antemano mi correo es leazo_114@hotmail.com

Pedro Cardenas Del Angel dijo...

Que tal mi estimado, oye no puedo descargar tu codigo, serias tan amable de subirlo en otro servidor, y pasar el link, bueno si esque puedes, (esta muy interesante el aplicativo)

Ivan Totomol dijo...

me podrias mandar el proyecto completo a mi correo por favor toto1088@live.com.mx

vivian dijo...

Hola, tengo un trabajo de la Universidad, debe hacer un chat en rmi para que transfiere un imagen, de un equipo a otro , podrias ayudarme o tiene algun codigo que me sirva para este trabajo . mi correo es vivice2@gmail.com

Pedro Cardenas Del Angel dijo...

Mandame tu proyecto a mi correo cardenas_clk@hotmail.com y te paso el mio que hice en mi residencia profecional RMI con base de datos mysql, imprime reporte con jasperreport y puede guardar imagenes a la base de datos. consultar actualizar, y tambien maneja usuarios, activa los menus de acuerdo a los privilegios, ejecutable tanto clinte como servidor. se histala en cualquier windows xp, 7, ahorita sigo programando ese sistema para titulacion, aunque me falta muchas cosas para implementarle

Jose Rodriguez dijo...

Excelente! Podrías mandarme el proyecto a la siguiente dirección: jose_gb@live.com.mx. Gracias de antemano

Anónimo dijo...

está excelente podrías enviarme el código porfavor? sería de mucha ayuda ana_15_darkangelikeangel@hotmail.com

Anónimo dijo...

codigo polfa parael_pool@yahoo.com.mx

Anónimo dijo...

hola que tal buenas noches lo molestaria si me pudiera enviar el codigo por favor

Pedro Cardenas Del Angel dijo...
Este comentario ha sido eliminado por el autor.
Pedro Cardenas Del Angel dijo...

Si quiere codigo o asesoria de RMI mandame correo asi,
ya que la primera vercion lo tengo en ejecutable;
y ahorita ya programe bastante y he modificado las tablas y bases de datos, modificado procedimientos, reportes,,, es mas los reportes antes los hacia desde el cliente (reportes sin conexion a bd ), ahora los genero en el servidor (reportes conectados a la base de datos) y los muestro en el cliente

/*creo que este cuate del blog ya se olvido*/
imaginate esto fue desde el 2007

Ramón Cossío Cruz dijo...

Hola. Excelente trabajo. Me interesaría tener los códigos. ¿Podrías enviármelos a este correo? ramoncossiocruz@gmail.com

Muchas gracias

Anónimo dijo...

Está extraordinario tu proyecto. Porfavor podrías enviarme el proyecto a sfiges_94@hotmail.com. Gracias de antemano. Dios te colme de bendiciones.

Anónimo dijo...

buenos dias , excelente . por favor.... christian1_48@hotmail.com ....... se le agradece de antemano

Luis Angel dijo...

Buenas Tardes me gustaria que me lo enviaras para revisarlo y checarlo, se me hace muy interesante mi correo es angel.rg.com@gmail.com

Pedro Cardenas Del Angel dijo...

no van a encontrar en la red un proyeto echo en rmi con base de datos. reprotes.. y nadie los puede pasar, necesitan migrar los programas en modo local, al rmi, cambiar la forma de mostrar los datos... y las llamadas..
yo hice un programa para residencia profesional en rmi con base de datos, y si me resulto muy dificl hacerlo pero lo hice, asi que nadie les puede pasar un proyecto completo

Nallely Lopez dijo...

hola, buenas tardes :)
excelente, me gustaria que me enviaras el codigo, porfavor, muchas gracias.
nallelylmtz80@gmail.com

Anónimo dijo...

hola me podrias enviar codigo a maycolmogollonr@hotmail.com

Anónimo dijo...

maycolmogollonr@hotmail.com codigo por favor

Anónimo dijo...

Hola Alberto te saluda
interesante podrias mandarme el codigo pa base del proyecto que quiero iniciar albert_win@hotmail.com

Anónimo dijo...

Buenas tardes,
me interesa mucho el codigo para labores academicas, podrias enviarme el codigo.
henaomarinalex@gmail.com

muchas gracias.

JESÚS VENTURA dijo...

Hola, te agradeceria mucho el codigo, charmin8526@gmail.com, gracias

JESÚS VENTURA dijo...

Hola, te agradeceria mucho el codigo, charmin8526@gmail.com, gracias

Publicar un comentario en la entrada