2012-06-15 51 views
9

Tôi đang viết một ứng dụng Trò chuyện dựa trên RMI nhỏ.RMI NotSerializableException mặc dù đó là một đối tượng ở xa

Ý tưởng là: Khách hàng đăng ký chính mình trên Máy chủ và mỗi lần máy chủ nhận được thông báo từ khách hàng, anh ấy gửi thông báo này đến tất cả các khách hàng khác.

Nhưng tôi nhận được NotSerializableException mặc dù, đối tượng, tôi chuyển qua như một tham số phương thức triển khai giao diện Từ xa.

Dưới đây là một số mã: (Phần vấn đề là this tham số trong this.chatServ.registriereClient(this); (ClientChat thực hiện))

The (ClientChat) giao diện:

public interface ChatClient extends Remote 
{ 

} 

(ClientChat) Thực hiệ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) Giao diện

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

} 

(ServerChat) Thực hiệ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); 
    } 
} 

Chủ đầu tư:

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

Ngoại lệ:

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 

Như đã nói, tôi tự hỏi tại sao tôi nhận được loại ngoại lệ này, mặc dù ChatClientImpl đã là Từ xa.

Hy vọng bạn có thể giúp tôi :)

Trả lời

14

Đối tượng truyền như tham số hoặc kết quả của phương pháp từ xa phải là:

  1. Serializable (hoặc Externalizable), hoặc

  2. xuất khẩu đối tượng từ xa.

Bạn cũng vậy. Tuy nhiên khi nó thực hiện một giao diện từ xa rõ ràng bạn dự định (2). Đối tượng mở rộng UnicastRemoteObject được tự động xuất khi xây dựng. Các đối tượng không được xuất khẩu rõ ràng, qua UnicastRemoteObject.exportObject().

+0

cách sử dụng nó trong các lớp máy khách và máy chủ, riêng biệt? – Usman

+0

@Usman Cách sử dụng cái gì? – EJP

1

Việc bạn có thể làm là thiết lập đối tượng gọi lại. Đây là một trong đó mở rộng UnicastRemoteObject và khi bạn vượt qua điều này nó sẽ trở thành một cuộc gọi lại.

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


Remote không phải là Serializable. Bạn không thể vượt qua một đối tượng proxy theo cách này. Ngay cả khi bạn đã làm cho nó Serializable nó sẽ gửi một bản sao của đối tượng mà sẽ tồn tại trên máy chủ. Bản sao của đối tượng trên máy khách sẽ không được gọi.

Đối với "máy chủ" của bạn để gửi tin nhắn tới "khách hàng", bạn phải tạo một dịch vụ trên "máy khách" để biến nó trở thành một máy chủ.

Bạn có thể thấy rằng việc sử dụng giải pháp nhắn tin như JMS phù hợp hơn với việc này. Máy chủ JMS có các chủ đề mà bạn có thể xuất bản và đăng ký. Một máy chủ JMS đơn giản để sử dụng là Active MQ.

+0

như vậy, nếu tôi hiểu bạn đúng, tôi không thể vượt qua một đối tượng từ xa thông qua một tham số cho máy chủ và để cho máy chủ gọi các phương thức khác trên đối tượng được truyền này? – Graslandpinguin

+0

Bạn có thể, nhưng đối tượng được gọi sẽ nằm trên máy chủ. Bạn không thể có nó gọi khách hàng từ máy chủ theo cách này. Có một số giao thức RPC có hỗ trợ điều này, nhưng tôi không nhớ nó (tôi đã viết một trong quá khứ;). Đối với một máy chủ trò chuyện, Chủ đề JMS là cách đơn giản nhất để thực hiện việc này. –

+0

Xem chỉnh sửa của tôi. Có một cách để làm với với RMI. –

-1

Đảm bảo rằng tên gói máy chủ phù hợp với khách hàng, nếu không, có thể ném MarshalException khi gọi đối tượng từ RMI Registry.

Nó thực sự là một điều đơn giản nhưng có thể xảy ra với bạn. Tôi hy vọng bạn thấy nó hữu dụng.

+0

Không trả lời câu hỏi. Điều này cần phải được đăng làm bình luận. – EJP

1

Hình như bạn có thể đã quên 'kéo dài UnicastRemoteObject' trên triển khai giao diện:

public class ChatClientImpl extends UnicastRemoteObject implements ChatClient{ 
} 

public class LobbyChatServerImpl extends UnicastRemoteObject implements ChatServer{ 
} 
Các vấn đề liên quan