【问题标题】:RMI: create server on certain net address and portRMI:在特定的网络地址和端口上创建服务器
【发布时间】:2016-07-26 09:09:25
【问题描述】:

我想在我以编程方式选择的端口和网络接口上创建 rmi 服务器(没有 jvm 设置)。例如我想要rmi服务器监听接口127.0.0.1和端口2525。我在互联网上阅读了资料,这就是我最终得到的解决方案。

class ServerSocketFactory implements RMIServerSocketFactory, Serializable {

    public ServerSocket createServerSocket(int port) throws IOException
    {
        ServerSocket server = new ServerSocket(2525, 0, InetAddress.getByName("127.0.0.1"));
        return server;
    }
}

这就是我创建注册表的方式

registry = LocateRegistry.createRegistry(2525,null,new ServerSocketFactory());

但是,我得到了异常:

java.rmi.server.ExportException: Port already in use: 2525; nested exception is: 
    java.net.BindException: Address already in use
    at sun.rmi.transport.tcp.TCPTransport.listen(TCPTransport.java:341)

我不明白为什么如果我在 createRegistry 中使用 ServerSocketFactory 还有一个端口参数。我的错误是什么?

附:这不是Remote method invocation port in use 的重复,因为它是关于选择网络接口而不是端口。

【问题讨论】:

  • @close-voter 不是那个问题的重复..

标签: java rmi


【解决方案1】:

BindException 表示该端口已在使用中。所以你运行这段代码两次,或者其他东西在端口上监听。

您不必指定端口号两次。只需使用作为参数提供给createServerSocket() 的端口号。它将是您在导出时指定的端口号,或者为零。

如果您使用此套接字工厂的多个实例,则需要在您的套接字工厂类中实现equals(),以便它为此类的所有实例返回true

注意RMIServerSocketFactory 的实现不需要是Serializable。事实上,除了绑定到 127.0.0.1 之外,您根本不需要 RMIServerSocketFactory 实现类。不清楚您为什么要这样做,因为这意味着您在同一主机中执行所有 RMI,这是徒劳的。

所以总的来说你需要:

registry = LocateRegistry.createRegistry(2525);

myObject = new MyRemoteObject(2525);

// constructor
public MyRemoteObject(int port) throws RemoteException
{
    super(port);
}

如果您需要远程对象(包括注册表)仅侦听一个本地 IP 地址而不是所有本地 IP 地址,那么您需要 RMIServerSocketFactory

public class MyRMIServerSocketFactory implements RMIServerSocketFactory
{
    private InetAddress address;

    public MyRMIServerSocketFactory(InetAddress address)
    {
        this.address = address;
    }

    @Override
    public ServerSocket createServerSocket(int port) throws IOException
    {
        return new ServerSocket(port, 0, address);
    }

    @Override
    public boolean equals(Object that)
    {
        return that != null && this.getClass() == that.getClass() && this.address.equals((MyServerSocketFactory)that).address);
    }
}

使用它:

Registry registry = LocateRegistry.createRegistry(2525, null, new MyServerSocketFactory(address));

public MyRemoteObject(int port, InetAddress address) throws RemoteException
{
    super(port, null, new MyServerSocketFactory(address);
}

这个游戏的规则是,当且仅当:

  1. 它们都不使用服务器套接字工厂,或者它们都使用equals()下相等的服务器套接字工厂
  2. 它们都使用相同的端口号,或者为零,或者没有端口号,或者在第一个导出的对象之后都使用零或没有端口号(当它们共享第一个端口时)。请注意,这意味着默认情况下会发生端口共享,前提是满足 (1)。

【讨论】:

  • @downvoter 如果您认为这里有问题,请说明是什么。但是,随机投票给人一种正确答案不正确的印象,从而误导 OP,在这里是不能容忍的。
  • 当我在创建注册表后发现我得到这个异常时,我执行 UnicastRemoteObject.export(obj,2525)。你能说我如何将对象导出到我用 createRegistry() 创建的套接字吗?老实说糟糕的 API。
  • 你已经做到了。不清楚你在问什么。当然,如果要共享端口,注册表和远程对象都必须在同一个 JVM 中,并且它们也必须使用相等的套接字工厂。不清楚您认为 API 有什么问题。
  • 我有 rmi 服务器 - 我们只谈论服务器,让我们完全忘记客户端。现在我有以下任务:1)为 RMI 创建我想要的套接字 2)在该套接字上创建注册表 3)将远程导出到该套接字。我做了任务 1 和 2。但我不知道怎么做 3。
  • 我刚刚回答了这个问题。你已经做到了。正如我的回答中已经建议的那样,我会摆脱套接字工厂,只需将您的注册表和远程对象都导出到您的端口上。您也不需要步骤 (1)。
猜你喜欢
  • 2017-04-28
  • 1970-01-01
  • 2012-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-14
  • 2022-11-03
相关资源
最近更新 更多