我想构建系统,以便: 1.客户端连接到服务器 2.客户要求端口为他服务 3.服务器创建一个远程对象来为客户端提供服务并将其绑定到端口 4.将端口号返回给客户端 5.客户端连接到端口
我的会话/连接管理器
public class ClientHandler extends UnicastRemoteObject implements Transfer
{
Registry rmi;
Registry reg;
PrintWriter log;
public Client client;
public ClientHandler(String ip, int port) throws RemoteException
{
super();
try
{
File f = new File(ip+" "+new Date()+".txt");
log = new PrintWriter(f);
}catch (Exception e)
{
e.printStackTrace();
}
rmi = LocateRegistry.createRegistry(port);
try
{
rmi.bind(String.valueOf(port),this);
}catch(Exception e)
{
e.printStackTrace();
}
}
会话实施
#dialog{
display: none;
}
#dialog:target{
display: block;
}
#close{
position: fixed;
opacity: 0;
}
#close:target + #dialog{
display: none;
}
如果在远程调用中创建对象,则会将其视为远程源,因此除非您在同一主机上,否则不允许将其绑定到LocalRegistry。和服务器抛出java.rmi.AccessException不允许使用Registry.Registry.bind:源IP地址是非本地主机。
答案 0 :(得分:2)
如果在远程调用中创建对象,则会将其视为远程源
不真实的。这根本不正确。你刚刚做到了这一点。别这么做。
所以除非你在同一台主机上,否则不允许将其绑定到LocalRegistry。
但你在同一台主机上。构造函数ClientHandler
与ConnectionManager
在同一主机中运行,并且它也在同一主机中创建Registry,
。实际上,所有这些都发生在同一个JVM中。
和服务器抛出java.rmi.AccessException不允许Registry.Registry.bind:源IP地址是非本地主机。
不,它没有。我测试了你的代码。修复编译错误后,它工作正常。无法重现。
<强>无论其强>
您不需要关于端口或额外绑定的部分。所有远程对象都可以共享同一个端口。服务器只需要直接将新的远程会话对象实例返回给客户端。
使用您的类名简单实现您的要求,如果您没有提供Server
界面,则需要进行一定程度的猜测:
public interface Server extends Remote
{
boolean checkConnection() throws RemoteException;
Transfer getSession(String ip) throws RemoteException;
}
public class ConnectionManager extends UnicastRemoteObject implements Server
{
public List<ClientHandler> clients = Collections.synchronizedList(new ArrayList<>());
public ConnectionManager() throws RemoteException
{
super();
}
public static final String RMI_ID = "Server";
@Override
public boolean checkConnection() throws RemoteException
{
return true;
}
@Override
public Transfer getSession(String ip) throws RemoteException
{
ClientHandler ch = new ClientHandler(ip);
clients.add(ch);
return ch;
}
}
public class ClientHandler extends UnicastRemoteObject implements Transfer
{
PrintWriter log;
public Client client;
public ClientHandler(String ip) throws RemoteException
{
super();
try
{
File f = new File(ip+" "+new Date()+".txt");
log = new PrintWriter(f);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
修改强>
从您的帖子和您的评论中可以清楚地看出,您对Java RMI存在一些重大误解:
导出对象的端口与注册表无关。
确定何时构建扩展UnicastRemoteObject
的对象,通过super()
,调用,或者为其他对象调用UnicastRemoteObject.exportObject()
时。如果提供非零端口号,则使用该端口,并且通常可以与其他远程对象共享。否则,如果已经使用了RMI端口,则与该对象共享,否则将获得系统分配的端口号。
请注意,导出步骤先于绑定步骤,因此您的错误概念不可能是正确的。
LocateRegistry.createRegistry()
,则从该JVM导出的所有其他远程对象都可以与注册表共享该端口。远程方法可以返回远程对象。
注册表就是一个例子:它实际上只是一个远程哈希映射。你的方法也可以做到。在返回过程中,对象将被其存根替换。
由于这些原因,您的设计完全是错误的,下面的评论完全是胡说八道。
补充说明:
RemoteServer.getClientHost().
ClientHandler
的构造函数不应该在内部捕获IOExceptions
:它应该将它们抛给调用者,因此调用者可以意识到问题。