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

标签 java rmi

我想在我以编程方式选择的端口和网络接口(interface)上创建 rmi 服务器(无需 jvm 设置)。例如我想要rmi服务器监听接口(interface)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());

但是,我遇到了异常(exception):

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 的重复项因为它是关于选择网络接口(interface)而不是端口。

最佳答案

BindException 表示该端口已在使用中。因此,您运行此代码两次,或者有其他东西正在端口监听。

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

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

注意,RMIServerSocketFactory 实现不需要是可序列化。事实上,除了绑定(bind)到 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);
}

这个游戏的规则是,当且仅当以下情况时,从同一 JVM(可以包括注册表)导出的远程对象之间共享端口:

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

关于java - RMI:在特定网络地址和端口上创建服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38585629/

相关文章:

java - RMI:ServerException、RemoteException、UnmarshalException、UnmarshalException

java - Spring JPA 存储库事务性

java - 速度加/减速度

java - 动态返回Java中所有类变量值的列表

java - RMI:检查客户端崩溃

java - 设置 rmiregistry 的堆大小

java - Netbeans、Ant 和 RMIC(Java RMIC 编译器)(帮助)

java - 当列类为 float 或 double 时如何将表格单元格设为空白

java - 调试器未在断点 : Websphere in Eclipse 处停止

java - JDK7u21 RMI 更改