2012-06-15 13 views
9

私は小さなRMIベースのチャットアプリケーションを作成しています。リモートオブジェクトですが、RMI NotSerializableExceptionです

考えられるのは、クライアントが自分自身をサーバーに登録し、サーバーがクライアントからメッセージを受信するたびに、このメッセージを他のすべてのクライアントにプッシュすることです。

しかし、私はメソッドパラメータとして渡していますが、リモートインタフェースを実装していますが、NotSerializableExceptionを受け取ります。

ここ

はいくつかのコードである: (問題の一部はthis.chatServ.registriereClient(this);(ClientChat実装)にthisパラメータである)

(ClientChat)インターフェース:

public interface ChatClient extends Remote 
{ 

} 

(ClientChat)実装:

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)インターフェイス

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

} 

(ServerChat)実装

public class LobbyChatServerImpl implements ChatServer 
{ 

    ArrayList<ChatClient> clientListe = null; 

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

クライアント:

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

サーバー:

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

例外:

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 

既に述べたように、ChatClientImplはすでにリモートですが、なぜ私はこの種の例外を取得するのだろうかと思います。

は、あなたが私を助けることを願って:)

答えて

14

リモートメソッドのパラメータまたは結果として渡されたオブジェクトのいずれかでなければならない:

  1. シリアライズ(または外部化)、又は

  2. リモートオブジェクトをエクスポート。

あなたはどちらもありません。しかし、それは明らかにあなたが意図したリモートインターフェイスを実装する(2)。 UnicastRemoteObjectに拡張されたオブジェクトは、構築時に自動エクスポートされます。オブジェクトを明示的にエクスポートする必要はありません。UnicastRemoteObject.exportObject()

+0

クライアントクラスとサーバークラスで別々に使用する方法は? – Usman

+0

@Usman何を使うの? – EJP

1

あなたが行うことができますどのようなセットアップは、コールバックオブジェクトです。これはUnicastRemoteObjectを継承するもので、これを渡すとコールバックになります。

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


Remote直列化可能ではありません。このようにプロキシオブジェクトを渡すことはできません。たとえそれをSerializableにしたとしても、サーバーに存在するオブジェクトのコピーを送信します。クライアント上のオブジェクトのコピーは呼び出されません。

"サーバー"が "クライアント"にメッセージを送信するには、 "クライアント"にサービスを作成してサーバーにする必要があります。

JMSなどのメッセージングソリューションを使用する方が適していることがあります。 JMSサーバには、パブリッシュとサブスクライブが可能なトピックがあります。使用する単純なJMSサーバはActive MQです。

+0

をので、私はあなたが右理解していれば、私は経由でリモートオブジェクトを渡すことはできませんパラメータをサーバに渡し、サーバがこの渡されたオブジェクトの他のメソッドを呼び出せるようにしますか? – Graslandpinguin

+0

できますが、呼び出されたオブジェクトはサーバー上にあります。この方法でサーバーからクライアントを呼び出させることはできません。これをサポートするいくつかのRPCプロトコルがありますが、私はこれを覚えていません(過去に書きました;)。チャットサーバの場合、これを行う最も簡単な方法はJMSトピックです。 –

+0

私の編集を参照してください。 RMIを使用する方法があります。 –

-1

サーバーのパッケージ名がクライアントのものと一致することを確認します。そうでない場合は、MarshalExceptionがRMIレジストリからオブジェクトを呼び出すときにスローされることがあります。

これは本当に簡単なことですが、あなたに起こる可能性があります。私はあなたがこれが有用であることを願っていますあなたがインターフェイスの実装上の「UnicastRemoteObjectをを拡張」に忘れていたかもしれないよう

+0

質問には答えません。これはコメントとして投稿されているはずです。 – EJP

1

が見える:

public class ChatClientImpl extends UnicastRemoteObject implements ChatClient{ 
} 

public class LobbyChatServerImpl extends UnicastRemoteObject implements ChatServer{ 
}