【问题标题】:Is it possible to use RMI bidirectional between two classes?是否可以在两个类之间使用 RMI 双向?
【发布时间】:2009-05-26 17:46:51
【问题描述】:

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

BR,

马库斯

【问题讨论】:

  • RMI 的替代方案是SIMON 框架。

标签: java connection rmi


【解决方案1】:

如果B 实现Remote,它可以被导出并在RMI 调用中作为参数传递给A。在这种情况下,不需要在 RMI 注册表中注册 B,因为客户端会显式传递对它的引用。

【讨论】:

  • Mhhh,我想如果我以这种方式实现它,“复制”和“真实”B之间可能会出现一些数据不一致,或者?
  • 不,没有“副本”。当 A 调用 B 上的方法时,它实际上是通过存根调用“真实” B 的远程方法调用。这与 B 调用 A 上的远程方法相同,只是 A 不是在注册表中查找对象,而是收到远程对象作为方法调用中的参数。
  • 但是,如果我没记错的话,这在 B 无法接受传入连接时不起作用,例如当它在带有 NAT 的消费者网络上时。有没有办法对已经存在的连接进行回调?
  • @BartvanHeukelom 在非常早期的 RMI 版本中,从服务器到客户端的流量可以通过从客户端到服务器的原始连接进行多路复用。但此功能已在 1.2.2 中弃用并删除。使用 RMI,“客户端”回调实际上是一个服务,“服务器”只有在打开返回给“客户端”的套接字后才能调用回调。
  • @erickson 您提到“它可以导出”。这意味着用于导出它的额外显式代码,或者幕后发生了一些魔术?如果你有很好的阅读参考,请分享。作为上下文:我试图在 Spring env 中实现双向通信,但也试图了解背后的过程
【解决方案2】:

我在客户端和服务器之间实现了 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);
        }
    }
}

【讨论】:

    【解决方案3】:

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

    但是,如果您有很多这样的 RMI 调用来回返回,您可能会遇到性能问题。

    【讨论】:

      【解决方案4】:

      如果您将B 作为参数传递给A 中的方法,然后使用该引用调用B 上的方法,我相当肯定反向连接已建立,并且我相当肯定RMI注册表是为B 所在的JVM 创建的。在某些时候,这给我们带来了一些特别严格的防火墙规则的麻烦。我们的代码看起来有点像

      网络服务器

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

      应用服务器

      public int attachFile(RemoteInputStream in){
          ...
      
          byte[] buffer;
          while((buffer = in.read(1024)) != null) // Would return null to indicate EOF
            // Do some stuff
      
          return documentId;       
      }
      

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

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

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

          【讨论】:

            【解决方案7】:

            某些 RMI 服务支持回调或侦听器,它们允许服务器异步调用同一连接下的客户端。 (对不起,我不记得这样做的开放图书馆的名称,快速谷歌不是很有帮助) 标准 RMI 不支持这一点,相反,您还需要将客户端公开为 RMI 服务。

            【讨论】:

              【解决方案8】:

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2014-05-09
                • 1970-01-01
                • 1970-01-01
                • 2014-05-10
                • 1970-01-01
                • 1970-01-01
                • 2014-09-21
                • 2023-01-12
                相关资源
                最近更新 更多