RMI:在特定的网络地址和端口上创建服务器

RMI: create server on certain net address and port

我想在我以编程方式选择的端口和网络接口上创建 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 时还有一个端口参数。我的错误是什么?

P.S。这不是 Remote method invocation port in use 的副本,因为它是关于选择网络接口而不是端口。

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

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

如果您正在使用此套接字工厂的多个实例,则需要在您的套接字工厂 class 中实施 equals(),以便它 returns true 用于所有class.

的实例

注意 RMIServerSocketFactory 实现不需要 Serializable。事实上,除了绑定到 127.0.0.1 之外,您根本不需要 RMIServerSocketFactory 实现 class。不清楚您为什么要这样做,因为这意味着您在同一主机内执行所有 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. none 其中使用服务器套接字工厂,或者全部使用在 equals()
  2. 下相同的服务器套接字工厂
  3. 它们都使用相同的端口号,或者为零,或者没有端口号,或者在第一个对象导出后全部使用零或没有端口号(当它们将共享第一个的端口时)。请注意,这意味着默认情况下会发生端口共享,前提是满足 (1)。