2012-06-15 5 views
9

Ich schreibe eine kleine RMI-basierte Chat-Anwendung.RMI NotSerializableException obwohl es ein Remote-Objekt ist

Die Idee ist: der Client registriert sich auf dem Server, und jedes Mal, wenn der Server eine Nachricht von einem Client erhält, schiebt er diese Nachricht an alle anderen Clients.

Aber ich erhalte eine NotSerializableException, obwohl das Objekt, das ich als Methodenparameter übergebe, die Remote-Schnittstelle implementiert. Hier

ist ein Code: (Der problematische Teil ist der this Parameter in this.chatServ.registriereClient(this); (ClientChat Implementation))

Die (ClientChat) Schnittstelle:

public interface ChatClient extends Remote 
{ 

} 

(ClientChat) Umsetzung:

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) Schnittstelle

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

} 

(ServerChat) Umsetzung

public class LobbyChatServerImpl implements ChatServer 
{ 

    ArrayList<ChatClient> clientListe = null; 

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

Auftraggeber:

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); 
    } 

Server:

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(); 
     } 
    } 

Ausnahme:

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 

Wie bereits erwähnt, frage ich mich, warum ich diese Art von Ausnahme bekomme, obwohl ChatClientImpl bereits Remote ist.

Hoffe Ihr könnt mir helfen :)

Antwort

14

Objekte als Parameter bzw. Ergebnisse der entfernten Methoden entweder müssen bestanden:

  1. Serialisierbar (oder Externalizable) oder

  2. entfernte Objekte exportiert.

Ihr ist weder. Da es sich jedoch um ein Remote-Interface handelt, haben Sie es eindeutig beabsichtigt (2). Objekte, die sich um UnicastRemoteObject erweitern, werden beim Bau automatisch exportiert. Objekte, die nicht exportiert werden, müssen explizit über UnicastRemoteObject.exportObject() exportiert werden.

+0

wie man es in Client- und Server-Klassen getrennt verwendet? – Usman

+0

@Usman Wie benutzt man was? – EJP

1

Was Sie tun können, das Einrichten eines Callback-Objekt ist. Dies ist eine, die UnicastRemoteObject erweitert, und wenn Sie dies übergeben, wird es zu einem Rückruf.

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


Remote ist nicht Serializable. Sie können ein Proxy-Objekt auf diese Weise nicht übergeben. Selbst wenn Sie es Serializable gemacht hätten, würde es eine Kopie des Objekts senden, das auf dem Server existieren würde. Die Kopie des Objekts auf dem Client würde nicht aufgerufen werden.

Damit Ihr "Server" Nachrichten an Ihren "Client" sendet, müssen Sie einen Dienst auf dem "Client" erstellen, um ihn zu einem Server zu machen.

Sie könnten feststellen, dass die Verwendung einer Messaging-Lösung wie JMS für diese Einstellung besser geeignet ist. Ein JMS-Server verfügt über Themen, die Sie veröffentlichen und abonnieren können. Ein einfacher zu verwendender JMS-Server ist Active MQ.

+0

so, wenn ich Sie richtig verstehe, kann ich nicht ein entferntes Objekt über einen Pass Parameter an den Server und lassen Sie den Server andere Methoden auf diesem übergebenen Objekt aufrufen? – Graslandpinguin

+0

Sie können, aber das Objekt wird auf dem Server sein. Sie können den Client auf diese Weise nicht vom Server aus aufrufen. Es gibt einige RPC-Protokolle, die dies unterstützen, aber ich erinnere mich nicht, welches (ich habe eines in der Vergangenheit geschrieben;). Für einen Chat-Server ist JMS Topics der einfachste Weg, dies zu tun. –

+0

Siehe meine Bearbeitung. Es gibt eine Möglichkeit, mit RMI umzugehen. –

-1

Stellen Sie sicher, dass die Serverpaketnamen mit denen des Clients übereinstimmen, andernfalls kann ein MarshalException beim Aufruf des Objekts von RMI Registry ausgelöst werden.

Es ist wirklich eine einfache Sache, aber kann dir passieren. Ich hoffe, Sie finden das nützlich.

+0

Beantwortet die Frage nicht. Dies hätte als Kommentar gepostet werden sollen. – EJP

1

Sieht aus wie Sie zu ‚UnicastRemoteObject erweitert‘ auf den Schnittstellenimplementierungen vielleicht vergessen haben:

public class ChatClientImpl extends UnicastRemoteObject implements ChatClient{ 
} 

und

public class LobbyChatServerImpl extends UnicastRemoteObject implements ChatServer{ 
} 
Verwandte Themen