2012-06-15 20 views
9

Estoy escribiendo una pequeña aplicación de Chat basada en RMI.RMI NotSerializableException aunque es un objeto remoto

La idea es la siguiente: el cliente se registra a sí mismo en el servidor, y cada vez que el servidor recibe un mensaje de un cliente, que empuja este mensaje a todos los demás clientes.

pero recibo un NotSerializableException si bien, el objeto, que estoy pasando como un parámetro del método implementa la interfaz remota.

Aquí hay un código: (La parte problemática es el parámetro this en this.chatServ.registriereClient(this); (Aplicación ClientChat))

El (ClientChat) Interfaz:

public interface ChatClient extends Remote 
{ 

} 

(ClientChat) Aplicación:

public class ChatClientImpl implements ChatClient 
{ 

    ChatServer chatServ; 
    String clientName; 

    public ChatClientImpl(String clientName, ChatServer chatServ) { 
     this.chatServ = chatServ; 
     this.clientName = clientName; 
     try { 
      this.chatServ.registriereClient(this); 
     } catch (RemoteException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

(ServerChat) Interfaz

public interface ChatServer extends Remote 
{ 
     void registriereClient(ChatClient client) throws RemoteException; 

} 

(ServerChat) Aplicación

public class LobbyChatServerImpl implements ChatServer 
{ 

    ArrayList<ChatClient> clientListe = null; 

    @Override 
    public void registriereClient(ChatClient client) { 
     System.out.println("Client registriert"); 
     this.clientListe.add(client); 
    } 
} 

Cliente:

public static void main(String[] args) { 
     ChatServer lobbyChatServer = null; 
     try { 
      Registry registry = LocateRegistry.getRegistry(Server.RMI_PORT); 
      lobbyChatServer = (ChatServer) registry.lookup("LobbyChatServer"); 

     } catch (RemoteException e) { 
      e.printStackTrace(); 
     } catch (NotBoundException e) { 
      e.printStackTrace(); 
     } 

     ChatClient lobbyChat = new ChatClientImpl(name, lobbyChatServer); 
    } 

Servidor:

public static void main(String[] args) { 
     try { 
      if (System.getSecurityManager() == null) { 
       System.setSecurityManager(new RMISecurityManager()); 
      } 

      Registry registry = LocateRegistry.getRegistry(RMI_PORT); 

      ChatServer lobbyChatStub = (ChatServer)UnicastRemoteObject.exportObject(new LobbyChatServerImpl(), 0); 
      registry.bind("LobbyChatServer", lobbyChatStub); 

     } catch (RemoteException e) { 
      e.printStackTrace(); 
     } catch (AlreadyBoundException e) { 
      e.printStackTrace(); 
     } 
    } 

Excepción:

java.rmi.MarshalException: error marshalling arguments; nested exception is: 
    java.io.NotSerializableException: de.XX.Chat.ChatClientImpl 
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:156) 
    at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194) 
    at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148) 
    at $Proxy0.registriereClient(Unknown Source) 
    at de.XX.Chat.ChatClientImpl.<init>(ChatClientImpl.java:19) 
    at de.XX.Client.main(Client.java:49) 
Caused by: java.io.NotSerializableException: de.XX.Chat.ChatClientImpl 
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180) 
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346) 
    at sun.rmi.server.UnicastRef.marshalValue(UnicastRef.java:292) 
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:151) 
    ... 5 more 

Como ya he dicho, me pregunto por qué recibo este tipo de Excepción, aunque ChatClientImpl ya es Remoto.

Espero que me puedan ayudar :)

Respuesta

14

objetos pasados ​​como parámetros o resultados de los métodos remotos deben ser:

  1. Serializable (o Externalizable), o

  2. Exportados objetos remotos.

El suyo no es. Sin embargo, como implementa una interfaz remota, claramente pretendía (2). Los objetos que se extienden UnicastRemoteObject se exportan automáticamente en la construcción. Los objetos que no se deben exportar explícitamente, a través del UnicastRemoteObject.exportObject().

+0

cómo usarlo en clases de cliente y servidor, por separado? – Usman

+0

@Usman ¿Cómo usar qué? – EJP

1

Lo que puede hacer es configurar un objeto de devolución de llamada. Este es uno que extiende UnicastRemoteObject y cuando lo pasa se convierte en una devolución de llamada.

http://www.cs.swan.ac.uk/~csneal/InternetComputing/RMIChat.html


Remote no es Serializable. No puede pasar un objeto proxy de esta manera. Incluso si lo hizo Serializable, enviaría una copia del objeto que existiría en el servidor. No se invocará la copia del objeto en el cliente.

Para su "servidor" para enviar mensajes a su "cliente" Hay que crear un servicio en el "cliente" para que sea un servidor.

es posible que el uso de una solución de mensajería tales como JMS se adapta mejor a esta toma. Un servidor JMS tiene temas que puede publicar y suscribirse. Un servidor JMS simple para usar es Active MQ.

+0

así, si le he entendido bien, no puedo pasar un objeto a distancia a través de una parámetro para el servidor y dejar que el servidor llame a otros métodos en este objeto pasado? – Graslandpinguin

+0

Puede, pero el objeto llamado estará en el servidor. No puede hacer que llame al cliente desde el servidor de esta manera. Hay algunos protocolos RPC que lo respaldan, pero no recuerdo cuál (ya escribí uno en el pasado;). Para un servidor de chat, JMS Topics es la forma más sencilla de hacerlo. –

+0

Ver mi edición. Hay una manera de hacerlo con RMI. –

-1

Asegúrese de que los nombres del paquete del servidor coincidan con los del cliente, de lo contrario, se puede generar una excepción MarshalException llamando al objeto desde el Registro RMI.

Es realmente algo sencillo, pero puede sucederle a usted. Espero que encuentres esto útil.

+0

No responde la pregunta. Esto debería haber sido publicado como un comentario. – EJP

1

Parece que se le haya olvidado a 'se extiende UnicastRemoteObject' en las implementaciones de interfaz:

public class ChatClientImpl extends UnicastRemoteObject implements ChatClient{ 
} 

y

public class LobbyChatServerImpl extends UnicastRemoteObject implements ChatServer{ 
}