Java RMI回调在表异常中没有这样的对象

时间:2015-06-07 10:00:05

标签: java callback rmi

我正在尝试使用RMI在Java中使用回调。

我在AWS上运行了一台服务器。我的客户端成功连接到服务器并注册回调。但是,在尝试调用它时,我在服务器端遇到以下异常:

java.rmi.NoSuchObjectException: no such object in table
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:276)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:253)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:162)
    at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194)
    at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148)
    at com.sun.proxy.$Proxy3.call(Unknown Source)
    at server.SimpleUpdateManager.callAll(SimpleUpdateManager.java:42)
    at server.Server$1.run(Server.java:77)
    at java.lang.Thread.run(Thread.java:745)

我不知道为什么会这样。我已经检查过rc(客户端上的RemoteCallback实现实例)没有被垃圾回收。你知道它为什么不起作用吗?

以下是我的远程接口:

public interface RemoteCallback extends Remote {
    void call() throws RemoteException;
}

public interface CallbackManager extends Remote{
    void register(RemoteCallback uc) throws RemoteException;
    void unregister(RemoteCallback uc) throws RemoteException;
    void callAll() throws RemoteException;
}

相关的服务器代码:

 public class SimpleUpdateManager implements CallbackManager {

  private HashSet<RemoteCallback> callbacks;

  public SimpleUpdateManager() {
     callbacks = new HashSet<>();
  }

  @Override
  public synchronized void register(RemoteCallback uc) {
     callbacks.add(uc);
     System.out.println("Callback registered");
  }

  @Override
  public synchronized void unregister(RemoteCallback uc) {
     callbacks.remove(uc);
  }

  @Override
  public synchronized void callAll() {

     ArrayList<RemoteCallback> toDelete = new ArrayList<>();

     for(RemoteCallback rc : callbacks) {
        try {
           rc.call();
           System.out.println("  Called one listener");
        } catch (RemoteException re) {
           re.printStackTrace();
           toDelete.add(rc);
        }
     }

     for(RemoteCallback rc :toDelete)
       unregister(rc);

     System.out.println("Called all listeners");
  }
}

Server类的摘录:

private static SimpleUpdateManager setupUpdateManager() {
    String name = "UpdateManager";
    SimpleUpdateManager sum = new SimpleUpdateManager();

    try {
        CallbackManager exp = (CallbackManager) UnicastRemoteObject.exportObject(sum, 1100);
        LocateRegistry.getRegistry().rebind(name, exp);
    }
    catch(RemoteException re) {
        System.out.println("Setting up update manager failed");
        re.printStackTrace();
    }
    return sum;
}

public static void runUpdateDaemon(SimpleUpdateManager sum) {

    Thread updateDaemon = new Thread(new Runnable() {
        @Override
        public void run() {
            while(true) {
                try {
                    System.out.println("I will try calling all listeners");
                    sum.callAll();
                    TimeUnit.SECONDS.sleep(5);
                }
                catch (InterruptedException ie) {
                    break;
                }
            }
        }
    });
    //updateDaemon.setDaemon(true);
    updateDaemon.start();
}

客户端代码:RemoteCallback实现

public class SimpleCallback  implements RemoteCallback {
    @Override
    public void call() throws RemoteException {
        System.out.println("Callback called");
    }

    @Override
    protected void finalize() {
        System.out.println("Callback gc'd");
    }
}

并注册回调

try {
     rc = new SimpleCallback();
     UnicastRemoteObject.exportObject(rc, 1100);
     ((CallbackManager) LocateRegistry.getRegistry(host).lookup("UpdateManager")).register(rc);
     System.out.println("Callback registered");
  }
  catch (RemoteException|NotBoundException re) {
     System.out.println("Cannot register callback");
     re.printStackTrace();
  }

1 个答案:

答案 0 :(得分:1)

以下是问题所在:

客户端位于防火墙后面,该防火墙不允许从服务器访问端口1100,因此DGC认为客户端已经崩溃,垃圾以某种方式收集了回调。

相关问题