远程对象不支持的方法

Method not Supported by Remote Object

我有两个应用程序。注册 RMI 对象的服务器应用程序和使用远程对象的客户端应用程序。在客户端中,我创建了一条消息 class 实现可序列化并将其发送到远程对象,但是在调用该方法时出现此错误:java.rmi.UnmarshalException:无法识别的方法哈希:远程对象不支持的方法。我在这里错过了什么?

客户端主要方法

package cryptocomclient;

import RemoteObject.CryptoComManager;
import clientUI.clientGui;
import clientUI.ClientPresenter;
import clientUI.LoginGui;
import java.rmi.*;

public class CryptoCom {


    public static void main(String[] args) {

        // Gets the remote object reference from RemoteObjectConnection
        RemoteObjectConnection netConn = new RemoteObjectConnection();
        CryptoComManager ccm = netConn.getCCM();

        // Passes the remote object into the client for use
        CryptoComClient client = new CryptoComClient(ccm);

        LoginGui loginGui = new LoginGui();
        loginGui.setVisible(true);
        clientGui clientGui = new clientGui();


        ClientPresenter presenter = new ClientPresenter(client, clientGui, loginGui);
        clientGui.setPresenter(presenter);
        loginGui.setPresenter(presenter);
        System.out.println("All systems good to go!");
    }

}

获取远程对象引用的连接

package cryptocomclient;

import RemoteObject.CryptoComManager;
import java.rmi.Naming;

public class RemoteObjectConnection {

    CryptoComManager ccm;

    RemoteObjectConnection() {
        pullFromRegistry();
    }

    // Will be used to pass the ccm to the client during dependancy injections
    // in the main method of the client app.
    public CryptoComManager getCCM() {return ccm;}

    // Looks up the name of the object in the registry and sets it's reference
    // to the ccm located here.
    private void pullFromRegistry() {
        try {
            ccm = (CryptoComManager)Naming.lookup(CryptoComManager.LOOKUPNAME);
            System.out.println("Remote object pulled from registry.");
        }
        catch (Exception e) {
            System.err.println("CrytpoComCilent: CryptoComManager exception: " + e.getMessage());
        }

    }

}

客户端

package cryptocomclient;

import RemoteObject.CryptoComManager;
import java.rmi.RemoteException;
import java.util.ArrayList;

public class CryptoComClient {

    private ArrayList<Message> receivedMessageList = new ArrayList<>();
    private String userName;
    private CryptoComManager ccm;

    // Constructor that takes in a reference to the remote object.
    public CryptoComClient(CryptoComManager ccm) {
        this.ccm = ccm;
    }
    //Constructor that takes no remote object reference (for testing)
    public CryptoComClient(){

    }

    // Creates a new instance of Message and returns it.
    public Message createNewMessage(String memo, String sender, String recipient) {
        //Encryption should be done here


        return new Message(memo, sender, recipient);

    }

    // Returns a message from the recived arrayList at the specified index.
    public Message openMessage(int index) {

        if (receivedMessageList.size() == 0) {
            return null;
        }

        return receivedMessageList.get(index);

    }

    // Takes in a message and sends the message to the remote object
    public void sendMessage(Message message) throws RemoteException {

        ccm.sendMessageToServer(message);

    }


    // Calls the remote object to get the stored messages then adds them to the
    // clients receivedMessageList
    public void getReceivedMessages() throws RemoteException {

        ArrayList<Message> receivedList = ccm.receiveMessagesFromServer(userName);

        for(Message message: receivedList) {
            receivedMessageList.add(message);
        }

    }

    // Removes a message from the received message arrayList
    public void removeReceivedMessage(Message message) {

        receivedMessageList.remove(message);

    }



    // Getters and setters for fields listed at the top
    public ArrayList<Message> getRecievedMessageList() {return receivedMessageList;}
    public void setReceivedMessageList(ArrayList<Message> recievedMessageList) {this.receivedMessageList = recievedMessageList;} 

    public String getUserName() {return userName;}
    public void setUserName(String userName) {this.userName = userName;}

    public CryptoComManager getCCM() {return ccm;}
    public void setCCM(CryptoComManager ccm) {this.ccm = ccm;}

}

远程对象接口

package RemoteObject;

import cryptocomclient.Message;
import java.rmi.*;
import java.util.ArrayList;

public interface CryptoComManager extends Remote{

    public final static String LOOKUPNAME = "CryptoComManager";
    public void sendMessageToServer(Message message) throws RemoteException;
    public ArrayList<Message> receiveMessagesFromServer(String userName) throws RemoteException;
}

远程对象实现

package RemoteObject;

import cryptocomclient.Message;
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.HashMap;

public class CryptoComManagerImpl extends UnicastRemoteObject implements CryptoComManager{

    private HashMap<String, ArrayList<Message>> messageMap = new HashMap<>();

    public CryptoComManagerImpl() throws RemoteException{
        super();
    }

    @Override
    public void sendMessageToServer(Message message) throws RemoteException {

        // Checks to see if the recipient already has an arraylist
        // If it doesn't creates a new arraylist with the recipient as the key
        if(!messageMap.containsKey(message.getRecipient())){
            messageMap.put(message.getRecipient(), new ArrayList<Message>());
        }

        // Gets the recipients Arraylist and adds the new message
        ArrayList<Message> recipientArrayList = messageMap.get(message.getRecipient());
        recipientArrayList.add(message);
    }

    @Override
    public ArrayList<Message> receiveMessagesFromServer(String userName) throws RemoteException {

        ArrayList<Message> arrayListToSendBack = messageMap.get(userName);
        messageMap.remove(arrayListToSendBack);
        return arrayListToSendBack;

    }

    public HashMap<String, ArrayList<Message>> getHashMap() {return messageMap;}




}

留言class

package cryptocomclient;

import java.io.Serializable;
import java.util.Objects;

public class Message implements Serializable{

    String memo,
           sender,
           recipient;

    public Message(String memo, String sender, String recipient) {
        this.memo = memo;
        this.sender = sender;
        this.recipient = recipient;
    }

    @Override
    public boolean equals(Object o) {

        if(o == this) {return true;}

        if(!(o instanceof Message)) {return false;}

        Message otherMessage = (Message)o;

        if(this.memo == otherMessage.memo &&
           this.sender == otherMessage.sender &&
           this.recipient == otherMessage.recipient) 
        {
            return true;
        }

        return false;

    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 41 * hash + Objects.hashCode(this.memo);
        hash = 41 * hash + Objects.hashCode(this.sender);
        hash = 41 * hash + Objects.hashCode(this.recipient);
        return hash;
    }

    public String getMemo() {return memo;}
    public void setMemo(String memo) {this.memo = memo;}

    public String getSender() {return sender;}
    public void setSender(String sender) {this.sender = sender;}

    public String getRecipient() {return recipient;}
    public void setRecipent(String recipient) {this.recipient = recipient;}

}

服务器应用程序

package cryptocomserver;

import java.rmi.*;
import RemoteObject.*;
import java.rmi.registry.LocateRegistry;

public class CryptoComServer {

    public static void main(String[] args) throws RemoteException {

        System.out.println("CryptoComServer starting...");

        System.out.println("Creating Registry...");

        // Creates and exports a Registry instance on the local host that
        // accepts request on port 1099
        LocateRegistry.createRegistry(1099);
        System.out.println("Registry created.");

        //System.setSecurityManager(new SecurityManager());
        //System.out.println("Security Manager installed, Setting up service");

        try {
            // Creates instance of CryptoComManagerImpl object
            CryptoComManagerImpl ccm = new CryptoComManagerImpl();

            System.out.println("Publishing CryptoComServer...");

            // Binds the object to the registry using the LOOKUPNAME
            Naming.rebind(CryptoComManager.LOOKUPNAME, ccm);

            System.out.println("CryptoComServer ready.");
        }
        catch (Exception e) {
            System.err.println(e);
            System.exit(1);

        }

    }

}

堆栈

run:
Oct 20, 2019 12:07:32 AM clientUI.clientGui sendButtonActionPerformed
SEVERE: null
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.UnmarshalException: unrecognized method hash: method not supported by remote object
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:389)
    at sun.rmi.transport.Transport.run(Transport.java:200)
    at sun.rmi.transport.Transport.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:835)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run[=17=](TCPTransport.java:688)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:283)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:260)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:161)
    at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:227)
    at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:179)
    at com.sun.proxy.$Proxy0.sendMessageToServer(Unknown Source)
    at cryptocomclient.CryptoComClient.sendMessage(CryptoComClient.java:45)
    at clientUI.ClientPresenter.send(ClientPresenter.java:42)
    at clientUI.clientGui.sendButtonActionPerformed(clientGui.java:258)
    at clientUI.clientGui.access[=17=]0(clientGui.java:19)
    at clientUI.clientGui.actionPerformed(clientGui.java:159)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
    at java.awt.Component.processMouseEvent(Component.java:6533)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
    at java.awt.Component.processEvent(Component.java:6298)
    at java.awt.Container.processEvent(Container.java:2238)
    at java.awt.Component.dispatchEventImpl(Component.java:4889)
    at java.awt.Container.dispatchEventImpl(Container.java:2296)
    at java.awt.Component.dispatchEvent(Component.java:4711)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4897)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4534)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4475)
    at java.awt.Container.dispatchEventImpl(Container.java:2282)
    at java.awt.Window.dispatchEventImpl(Window.java:2746)
    at java.awt.Component.dispatchEvent(Component.java:4711)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:760)
    at java.awt.EventQueue.access0(EventQueue.java:97)
    at java.awt.EventQueue.run(EventQueue.java:709)
    at java.awt.EventQueue.run(EventQueue.java:703)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:90)
    at java.awt.EventQueue.run(EventQueue.java:733)
    at java.awt.EventQueue.run(EventQueue.java:731)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:730)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Caused by: java.rmi.UnmarshalException: unrecognized method hash: method not supported by remote object
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:327)
    at sun.rmi.transport.Transport.run(Transport.java:200)
    at sun.rmi.transport.Transport.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:835)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run[=17=](TCPTransport.java:688)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

Message.java class 存在于服务器和客户端应用程序中,但未打包在完全相同的文件结构中。我重构了结构,使 Message、RemoteObjectManager 和 RemoteObjectManagerImpl 都在同一个包中,并且这些包在各自的应用程序中的名称相同,现在一切正常。