首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RMI Stubs:强制客户端的主机值

RMI Stubs:强制客户端的主机值
EN

Stack Overflow用户
提问于 2017-09-05 15:04:59
回答 2查看 652关注 0票数 1

我们希望从网络中的不同主机访问相同的RMI服务器(dev-pc通过ssh隧道,jenkins-server通过直接连接)。问题是RMI主机在不同的客户端主机上以不同的名称已知。

当我们连接到注册表时,这不是一个问题,因为我们可以像这样设置目标主机名:

代码语言:javascript
复制
Registry registry = LocateRegistry.getRegistry("hostname", 10099, new CustomSslRMIClientSocketFactory());

但是,当我们像下面这样查找远程对象时,它包含错误的主机名。

代码语言:javascript
复制
HelloRemote hello = (HelloRemote) registry.lookup(HelloRemote.class.getSimpleName());

在调试器中,我可以看到主机类似于Registry,而不是Stub上的:

当我们调用Stub上的方法时,我们就会得到一个连接超时。如果我在调试器中手动将主机值更改为localhost,则方法调用将成功。

我知道我可以在服务器端设置java.rmi.server.hostname,但是来自jenkins的连接不再工作了。最简单的解决方案是,我强制RMI使用与从该注册表检索的所有Stub的注册表相同的主机。有比通过反射替换Stub中的主机值更好的方法吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-09-05 21:46:06

不幸的是,RMI有一个深层次的内置假设,即服务器主机有一个“最公共的”IP地址或主机名。这就解释了java.rmi.server.hostname的惨败。如果你的系统不符合,你就倒霉了。

票数 0
EN

Stack Overflow用户

发布于 2017-09-07 08:19:28

正如EJP指出的那样,似乎没有优雅的开箱即用的解决方案。我能想到两个不雅的:

  1. 更改每个客户端主机上的网络配置,以便将通信量重定向到不可访问的ip到本地主机。
  2. 通过反射更改"hello"-object上的主机值。

我选择了第二种选择,因为我所处的是一个测试环境,所讨论的代码无论如何都不会有效率。我建议不要这样做,因为这段代码可能会与java的未来版本发生冲突,如果安全管理器已经到位,它将无法工作。

但是,在这里,我的工作代码:

代码语言:javascript
复制
private static void forceRegistryHostNameOnStub(Object registry, Object stub) {
    try {
        String regHost = getReferenceToInnerObject(registry, "ref", "ref", "ep", "host").toString();

        Object stubEp = getReferenceToInnerObject(stub, "h", "ref", "ref", "ep");
        Field fStubHost = getInheritedPrivateField(stubEp, "host");
        fStubHost.setAccessible(true);
        fStubHost.set(stubEp, regHost);
    } catch (Exception e) {
        LOG.error("Applying the registry host to the Stub failed.", e);
    }
}

private static Object getReferenceToInnerObject(Object from, String... objectHierarchy) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
    Object ref = from;
    for (String fieldname : objectHierarchy) {
        Field f = getInheritedPrivateField(ref, fieldname);
        f.setAccessible(true);
        ref = f.get(ref);
    }
    return ref;
}

private static Field getInheritedPrivateField(Object from, String fieldname) throws NoSuchFieldException {
    Class<?> i = from.getClass();
    while (i != null && i != Object.class) {
        try {
            return i.getDeclaredField(fieldname);
        } catch (NoSuchFieldException e) {
            // ignore
        }
        i = i.getSuperclass();
    }
    return from.getClass().getDeclaredField(fieldname);
}

Stub上的方法调用现在成功了:

代码语言:javascript
复制
Registry registry = LocateRegistry.getRegistry("hostname", 10099, new CustomSslRMIClientSocketFactory());
HelloRemote hello = (HelloRemote) registry.lookup(HelloRemote.class.getSimpleName());
forceRegistryHostNameOnStub(registry, hello); // manipulate the stub
hello.doSomething(); // succeeds
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46058176

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档