问题 是否可以在两个类之间使用RMI双向?


我想在两个类(A和B)之间共享一些信息,它们运行在不同的java程序中。我没有编写完整的通信协议,而是想为此目的使用java内置rmi类。目前,B类能够远程运行属于A类的方法。是否有可能在A类中使用相同的“连接”来调用B类的方法?否则我可能要实施第二个rmi服务......

BR,

马库斯


11420
2018-05-26 17:46


起源

RMI的另一种选择是 SIMON 框架。 - schlamar


答案:


如果 B 器物 Remote,它可以导出并作为RMI调用中的参数传递给 A。在这种情况下,无需注册 B 在RMI注册表中,因为客户端正在明确地传递对它的引用。


9
2018-05-26 18:16



嗯,我想如果我这样实现它可能会出现“复制”和“真实”B之间的一些数据不一致,或者? - Markus
不,没有“副本”。当A在B上调用方法时,它实际上是通过存根调用远程方法调用“真实”B.它与B在A上调用远程方法相同,除了不是在注册表中查找对象,而是收到远程对象作为方法调用中的参数。 - erickson
但是,如果我没有弄错的话,当B无法接受传入连接时,这将不起作用,例如:当它在具有NAT的消费者网络上时。有没有办法对现有连接进行回调? - Bart van Heukelom
@BartvanHeukelom在早期版本的RMI中,从服务器到客户端的流量可以通过客户端到服务器的原始连接进行多路复用。但是在1.2.2中已弃用并删除了此功能。使用RMI,“客户端”回调实际上是一种服务,“服务器”只能在打开套接字回到“客户端”后调用回调。 - erickson


我在cleint和server之间实现了2路RMI,服务器使用Registry公开它的存根

  1. 客户端获取服务器的存根
  2. 然后客户端将其存根作为Observer放入服务器的addObserver方法
  3. 服务器使用此存根通知客户端

以下代码将提供更好的主意

import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;
import java.util.Observable;
import java.util.Observer;
import java.net.*;

import javax.rmi.ssl.SslRMIClientSocketFactory;
import javax.rmi.ssl.SslRMIServerSocketFactory;

interface ReceiveMessageInterface extends Remote
{
    /**
     * @param x
     * @throws RemoteException
     */
    void receiveMessage(String x) throws RemoteException;

    /**
     * @param observer
     * @throws RemoteException
     */
    void addObserver(Remote observer) throws RemoteException;
}

/**
 * 
 */
class RmiClient extends UnicastRemoteObject
{
    /**
     * @param args
     */
    static public void main(String args[])
    {
        ReceiveMessageInterface rmiServer;
        Registry registry;
        String serverAddress = args[0];
        String serverPort = args[1];
        String text = args[2];
        System.out.println("sending " + text + " to " + serverAddress + ":" + serverPort);
        try
        { // Get the server's stub
            registry = LocateRegistry.getRegistry(serverAddress, (new Integer(serverPort)).intValue());
            rmiServer = (ReceiveMessageInterface) (registry.lookup("rmiServer"));

            // RMI client will give a stub of itself to the server
            Remote aRemoteObj = (Remote) UnicastRemoteObject.exportObject(new RmiClient(), 0);
            rmiServer.addObserver(aRemoteObj);

            // call the remote method
            rmiServer.receiveMessage(text);
            // update method will be notified
        }
        catch (RemoteException e)
        {
            e.printStackTrace();
        }
        catch (NotBoundException e)
        {
            System.err.println(e);
        }
    }

    public void update(String a) throws RemoteException
    {
        // update should take some serializable object as param NOT Observable
        // and Object
        // Server callsbacks here
    }
}

/**
 * 
 */
class RmiServer extends Observable implements ReceiveMessageInterface
{
    String address;
    Registry registry;

    /**
     * {@inheritDoc}
     */
    public void receiveMessage(String x) throws RemoteException
    {
        System.out.println(x);
        setChanged();
        notifyObservers(x + "invoked me");
    }

    /**
     * {@inheritDoc}
     */
    public void addObserver(final Remote observer) throws RemoteException
    {
        // This is where you plug in client's stub
        super.addObserver(new Observer()
        {
            @Override
            public void update(Observable o,
                Object arg)
            {
                try
                {
                    ((RmiClient) observer).update((String) arg);
                }
                catch (RemoteException e)
                {

                }
            }
        });
    }

    /**
     * @throws RemoteException
     */
    public RmiServer() throws RemoteException
    {
        try
        {
            address = (InetAddress.getLocalHost()).toString();
        }
        catch (Exception e)
        {
            System.out.println("can't get inet address.");
        }
        int port = 3232;
        System.out.println("this address=" + address + ",port=" + port);
        try
        {
            registry = LocateRegistry.createRegistry(port);
            registry.rebind("rmiServer", this);
        }
        catch (RemoteException e)
        {
            System.out.println("remote exception" + e);
        }
    }

    /**
     * 
     * @param args
     */
    static public void main(String args[])
    {
        try
        {
            RmiServer server = new RmiServer();
        }
        catch (Exception e)
        {
            e.printStackTrace();
            System.exit(1);
        }
    }
}

4
2017-10-05 11:08





自从我使用RMI已经有一段时间了,但是如果B类实现的话,那就是IIRC java.rmi.Remote 并将对其自身实例的引用作为参数传递给类A中的方法,然后类A应该接收存根,并且将在原始实例上调用在其上调用的方法。

但是,如果你有很多这样的RMI调用,那么你可能会遇到性能问题。


1
2018-05-26 17:55





如果你通过 B 作为一个方法的参数 A 然后使用该引用调用方法 B 我相当确定建立了反向连接,并且我相当确定RMI Registry是为JVM创建的 B 驻留。在某些时候,这使我们遇到了特别严格的防火墙规则的麻烦。我们的代码看起来有点像

网络服务器

public int uploadFile(FileItem fileItem){
    return ApplicationClassLoader
        .get(DocumentManager.class)
        .attachFile(new RemoteInputStreamImpl(fileItem.getInputStream());
    )
}

Application Server

public int attachFile(RemoteInputStream in){
    ...

    byte[] buffer;
    while((buffer = in.read(1024)) != null) // Would return null to indicate EOF
      // Do some stuff

    return documentId;       
}

1
2018-05-26 21:11





没有第二个RMI服务器,B类如何知道A类?我想你将需要两台服务器。


-1
2018-05-26 17:49





两个JVM都需要实现RMI服务。但是,查看java.rmi中的各种类非常容易。

你不能做的是以某种方式使用一个RMI连接并进行双向通信。


-1
2018-05-26 18:09





某些RMI服务支持回调或侦听器,允许服务器在同一连接上异步调用客户端。 (对不起,我不记得开放库的名称,这样做,快速谷歌不是很有帮助) 标准RMI不支持此功能,您也需要将客户端公开为RMI服务。


-1
2018-05-26 22:04





RMI双向:

服务器:

import java.io.IOException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class RMISERVER {

   public RMISERVER() throws IOException {

       Thread t;
        try {
            t = new Prou_run();
            t.start();
        } catch (RemoteException ex) {
            Logger.getLogger(RMISERVER.class.getName()).log(Level.SEVERE, null, ex);
        }

   }


   public static void main(String args[]) throws IOException {
     new RMISERVER();
   }
}


import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.Naming;
import java.rmi.Remote;
import java.rmi.registry.Registry;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.tree.DefaultMutableTreeNode;

//extends java.rmi.server.UnicastRemoteObject
public class Prou_run extends Thread implements Runnable{

            New_Object  root = null,root2=null,root3=null,root4=null,root5;
              New_Object new_root=null;
            Object xt = null, xt2=null , xt3=null;
            Registry r1,r2;
            RMIClientSocketFactory csf,csf2;
            RMIServerSocketFactory ssf,sf2;


            new_Patryk npal;

 public Prou_run() throws java.rmi.RemoteException, IOException
 {
         if (System.getSecurityManager() == null) {
            System.setSecurityManager(new SecurityManager());
                  }

//            csf = new RMIClientSocketFactory() {
//
//                public Socket createSocket(String host, int port) throws IOException {
//                    return new Socket("rmi://localhost/getchil",1080);
//                }
//            };
//            csf2 = new RMIClientSocketFactory() {
//
//                public Socket createSocket(String host, int port) throws IOException {
//                   return new Socket("rmi://localhost/getchild",1081);
//                }
//            };
//            ssf=new RMIServerSocketFactory() {
//
//                public ServerSocket createServerSocket(int port) throws IOException {
//                    return new ServerSocket(1099);
//                }
//            };// ssf.createServerSocket(1099);
//              sf2=new RMIServerSocketFactory() {
//
//                public ServerSocket createServerSocket(int port) throws IOException {
//                   return new ServerSocket(1098);
//                }
//            };//sf2.createServerSocket(1098);
       try {
         r1=java.rmi.registry.LocateRegistry.createRegistry(1098);
                 r2=java.rmi.registry.LocateRegistry.createRegistry(1099);//, csf2, ssf);
                 java.rmi.registry.LocateRegistry.createRegistry(1097);
                 java.rmi.registry.LocateRegistry.createRegistry(1095);
                 java.rmi.registry.LocateRegistry.createRegistry(1096);
         System.out.println("RMI registry ready.");
      } catch (Exception e) {
         System.out.println("Exception starting RMI registry:");
         e.printStackTrace();
      }
        this.xt = null;this.xt2 = null;this.xt3 = null;
        npal = new new_Patryk();
        System.out.println("sdmmmfxxxxxxxx");

   }






    public void run() {

//while(true){

      try{

//             root =  new_root;
//             xt=npal.getChild((File)new_root.getob(), (int)new_root.geti());
             New_ObjectIMPL sl = new New_ObjectIMPL();
             sl.i=354;
                System.out.println("sdmmmf2");
                //r2
             Naming.rebind("rmi://localhost:1099/getchild",(New_Object) sl);
                System.out.println("sdmmmf3");

         }catch (Exception e) {
       System.out.println("Trouble: " + e);
     }

        while(new_root==null){
            try{
                 //System.out.println("sdmmmf1"   +   new_root.geti());
         new_root = (New_Object) Naming.lookup("rmi://localhost:1080/getchil");
         System.out.println("sdmmmf1"   +   new_root.geti());
            }catch (Exception e) {
       System.out.println("Trouble: " + e);
     }
        }
    }

}

























/**
 *
 * @author austinchuma
 */
public interface New_Object extends java.rmi.Remote {

     public int geti() throws java.rmi.RemoteException;

     public Object getob() throws java.rmi.RemoteException;

     public Object getobchild() throws java.rmi.RemoteException;

      public boolean getbbol() throws java.rmi.RemoteException;

       public byte[] getb() throws java.rmi.RemoteException;



}





public class New_ObjectIMPL extends java.rmi.server.UnicastRemoteObject implements New_Object

{
   Object ob = null,obchild = null;
    int  i=0;
    boolean bol = false;
    byte[] b = null;

    public New_ObjectIMPL() throws RemoteException{
        ob = null;obchild = null;
        i=0;
        bol = false;
        b = null;
    }

    public int geti() throws RemoteException {
       return i;
           }

    public Object getob() throws RemoteException {

       return ob;
    }

    public Object getobchild() throws RemoteException {
       return obchild;
    }

    public boolean getbbol() throws RemoteException {
      return bol;
    }

    public byte[] getb() throws RemoteException {

        return b;

    }


}

-1
2017-07-24 10:52



请检查格式 - user35443