我想在我以编程方式选择的端口和网络接口(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(可以包括注册表)导出的远程对象之间共享端口:
- 它们都不使用服务器套接字工厂,或者全部使用在
equals()
下相等的服务器套接字工厂 - 它们都使用相同的端口号,或者为零,或者不使用端口号,或者在导出的第一个对象之后全部使用零或不使用端口号(当它们共享第一个端口号时)。请注意,这意味着如果满足 (1),则默认情况下会发生端口共享。
关于java - RMI:在特定网络地址和端口上创建服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38585629/