RMI实施会话管理

时间:2015-06-16 14:40:46

标签: java session rmi

我想构建系统,以便: 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地址是非本地主机。

1 个答案:

答案 0 :(得分:2)

  

如果在远程调用中创建对象,则会将其视为远程源

不真实的。这根本不正确。你刚刚做到了这一点。别这么做。

  

所以除非你在同一台主机上,否则不允许将其绑定到LocalRegistry。

但你在同一台主机上。构造函数ClientHandlerConnectionManager在同一主机中运行,并且它也在同一主机中创建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存在一些重大误解:

  • 如果在远程呼叫中创建了远程对象,则被视为远程来源&#39;
  • 导出对象的端口与注册表无关。

    确定何时构建扩展UnicastRemoteObject的对象,通过super(),调用,或者为其他对象调用UnicastRemoteObject.exportObject()时。如果提供非零端口号,则使用该端口,并且通常可以与其他远程对象共享。否则,如果已经使用了RMI端口,则与该对象共享,否则将获得系统分配的端口号。

    请注意,导出步骤先于绑定步骤,因此您的错误概念不可能是正确的。

  • 您不需要在同一主机中运行多个注册表。您可以使用单个名称并将多个名称绑定到该名称。
  • 如果您第一次调用LocateRegistry.createRegistry(),则从该JVM导出的所有其他远程对象都可以与注册表共享该端口。
  • 远程方法可以返回远程对象。

    注册表就是一个例子:它实际上只是一个远程哈希映射。你的方法也可以做到。在返回过程中,对象将被其存根替换。

由于这些原因,您的设计完全是错误的,下面的评论完全是胡说八道。

补充说明:

  • 无所事事的方法并不能真正检查连接。创建 new 连接并检查它的可能性也很大。连接在RMI中确实不存在,或者至少它们对你很隐蔽,汇集,过期等等。
  • 您不需要传递客户端的IP地址。您可以从RemoteServer.getClientHost().
  • 在服务器上获取它
  • ClientHandler的构造函数不应该在内部捕获IOExceptions:它应该将它们抛给调用者,因此调用者可以意识到问题。