简体   繁体   English

不能使用 RMI 远程方法

[英]Can't use RMI remote methods

cant fix this for 3 days. 3天无法解决这个问题。 RMI works correctly with localhost or 192.168.* on 1 or 2 PCs,but remote clients cant use remote methods. RMI 在 1 或 2 台 PC 上使用 localhost 或 192.168.* 正常工作,但远程客户端不能使用远程方法。 Starting rmiregisry,then binding service with Naming.rebind()启动 rmiregisry,然后使用 Naming.rebind() 绑定服务

Registry IS CREATING successfuly,i can get list of binded services,but i cant even use any method.注册表创建成功,我可以获得绑定服务的列表,但我什至无法使用任何方法。

Searching remote service with搜索远程服务

Naming.lookup("rmi://host_ip:1099/qwe). 
or
Registry reg = LocateRegistry.getRegistry("host_ip",server);
reg.lookup("qwe")

Client finds the object but cant use it`s methods.客户端找到对象但不能使用它的方法。

Here is the code: Server.java:这是代码:Server.java:

public class Server extends UnicastRemoteObject{

protected Server() throws RemoteException {
}

public static void main(String[] args) throws InterruptedException, RemoteException {
    ServiceServerImpl server = new ServiceServerImpl();
    try {
        System.setProperty("java.rmi.server.hostname", "host_ip");
        Naming.rebind("/qwe", server);
        Arrays.asList(Naming.list("rmi://localhost")).forEach(System.out::println);
        System.out.println(System.getProperty("java.rmi.server.hostname"));
    } catch (Exception e) {
        e.printStackTrace();
    }
    server.startServer();
}
}

ServiceServer.java:服务服务器.java:

public interface ServiceServer extends Remote{
String[] getLoginsList() throws RemoteException;
void addLogin(String login) throws RemoteException;
void removeLogin(String login) throws RemoteException;
boolean canConnect(String login) throws RemoteException;
void setConnected(String login) throws RemoteException;
void setDisconnected(String login) throws RemoteException;
}

ServiceServerImpl.java(if needed): ServiceServerImpl.java(如果需要):

public class ServiceServerImpl extends UnicastRemoteObject implements ServiceServer {
private ServerSocket socketListener;
private Socket clientSock;
private volatile List<ClientHandler> threadsList = new ArrayList<ClientHandler>();
private volatile Map<String, Boolean> logins = new HashMap<String,Boolean>();
// private Timer timer;

public ServiceServerImpl() throws RemoteException {
}

public void startServer() {
    // startTimer();
    try {
        socketListener = new ServerSocket(5001);
        System.out.println("server up...");
        while (true) {
            clientSock = null;
            while (clientSock == null)
                clientSock = socketListener.accept();
            ClientHandler curClientHandler = new ClientHandler(clientSock, this);
            threadsList.add(curClientHandler);
            System.out.println("user connected: " + clientSock.getInetAddress());
        }
    } catch (Exception e) {
        System.err.println("Socket exception");
        e.printStackTrace();
    }
}

public synchronized void removeUserThread(ClientHandler handler) {
    try {
        threadsList.remove(handler);
    } catch (NullPointerException e) {
    }
    System.out.println("- 1");
}

@Override
public void setConnected(String login){
    logins.put(login,true);
}

@Override
public void setDisconnected(String login){
    logins.put(login,false);
}

@Override
public boolean canConnect(String login) throws RemoteException{
    return logins.keySet().contains(login)&& (!logins.get(login));
}

@Override
public String[] getLoginsList() throws RemoteException {
    return this.logins.keySet().toArray(new String[this.logins.size()]);
}

@Override
public void addLogin(String login) throws RemoteException {
    logins.put(login, false);
    System.out.println("added");
}

@Override
public void removeLogin(String login) throws RemoteException {
    logins.remove(login);
}


public Map<String, Boolean> getLogins() {
    return logins;
}

public Set<String> getAllowedLogins() {
    return logins.keySet();
}

public List<ClientHandler> getThreadsList() {
    return threadsList;
}
}

Im starting rmiregistry with cmd or with eclipse,then starting the Sever.我用 cmd 或 eclipse 启动 rmiregistry,然后启动服务器。 It starts correctly and I cant connect with localhost or 192.168.0.* BUT IT DOESNT WORK for remote clients Tried to use .policy files- still doesnt work它正确启动,我无法连接本地主机或 192.168.0。* 但它对远程客户端不起作用 尝试使用 .policy 文件 - 仍然不起作用

i get next Error code:我得到下一个错误代码:

Exception in thread "main" java.rmi.ConnectException: Connection refused to host: 192.168.0.83; nested exception is: 
java.net.ConnectException: Connection timed out: connect
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(Unknown Source)
at sun.rmi.transport.tcp.TCPChannel.createConnection(Unknown Source)
at sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source)
at sun.rmi.server.UnicastRef.invoke(Unknown Source)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)
at com.sun.proxy.$Proxy0.canConnect(Unknown Source)
at server.Main.main(Main.java:16)
Caused by: java.net.ConnectException: Connection timed out: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(Unknown Source)
at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(Unknown Source)
... 8 more

Help please请帮忙

You need to:你需要:

  1. Set java.rmi.server.hostname to the external IP address of your system, that is to say the public IP address of your router.java.rmi.server.hostname设置为您系统的外部IP 地址,即您的路由器的公共 IP 地址。
  2. Export your remote object(s) on a fixed port number, via super(port) .通过super(port)在固定端口号上导出远程对象。
  3. Arrange port forwarding in your router for those ports and port 1099.在路由器中为这些端口和端口 1099 安排端口转发。

How to do (3) is router-dependent and off topic.怎么做(3)取决于路由器并且偏离主题。

From your description, you have a general network connection problem, which is not specific to RMI.根据您的描述,您遇到了一般网络连接问题,这不是 RMI 特有的。 My advice is to put aside RMI and work with netcat or some other generic client/server implementation until you get the connection stuff sorted out, and then go back to RMI.我的建议是把 RMI 放在一边,使用 netcat 或其他一些通用的客户端/服务器实现,直到你解决了连接问题,然后再回到 RMI。

My guess is that there are at least two layers of security that you have to cross.我的猜测是您必须跨越至少两层安全性。 One is that the PC which is running the RMI server is blocking connections on all ports or maybe all but a small list of ports.一个是运行 RMI 服务器的 PC 正在阻止所有端口上的连接,或者可能除了一小部分端口之外的所有端口。 You will first need to open port 1099 (which is the default RMI port, of course you can choose something else) on the RMI host.您首先需要在 RMI 主机上打开端口 1099(这是默认的 RMI 端口,当然您可以选择其他端口)。 If you do that, you should be able to connect to the RMI host from another host on the same local network (ie on the same subnetwork 192.168.something.something).如果这样做,您应该能够从同一本地网络(即同一子网 192.168.something.something)上的另一台主机连接到 RMI 主机。

If you get that connection working, the next bridge to cross is that the router on the local network is probably blocking traffic from outside the local network.如果该连接正常工作,下一个要跨越的桥梁是本地网络上的路由器可能会阻止来自本地网络外部的流量。 Bear in mind that this is an important security measure.请记住,这是一项重要的安全措施。 My advice is to avoid opening a connection directly to the RMI host from the outside, since that is a security risk.我的建议是避免从外部直接打开与 RMI 主机的连接,因为这存在安全风险。 Instead try to set up an SSH tunnel and then use the tunnel to carry the connection from outside to the RMI host.而是尝试建立一个 SSH 隧道,然后使用该隧道将连接从外部传送到 RMI 主机。 SSH tunneling isn't too complicated; SSH 隧道并不太复杂; a web search should turn up an explanation.网络搜索应该会出现解释。

Clients might also be blocking outbound connections to port 1099;客户端也可能会阻止到端口 1099 的出站连接; you will have to enable those connections, or use SSH tunneling to avoid the problem.您必须启用这些连接,或使用 SSH 隧道来避免该问题。

In the early days (circa 1999) I set up a global network (well, about 4 sites) which communicated via RMI.在早期(大约 1999 年),我建立了一个通过 RMI 进行通信的全球网络(好吧,大约有 4 个站点)。 There was no obstacle with network security at the time.当时网络安全没有任何障碍。 So it is certainly possible to communicate remotely via RMI, you just have to get through the firewalls.因此当然可以通过 RMI 进行远程通信,您只需要通过防火墙。 Good luck and have fun.祝好运并玩得开心点。

192.168.XX is a private/Class C IP address which identifies your machine on your local network. 192.168.XX是私有/C 类 IP 地址,用于在本地网络上标识您的机器。 To expose your services to others/internet users, you will need to configure port forwarding on your router.要将您的服务公开给其他人/互联网用户,您需要在路由器上配置端口转发。 It also helps to use a free dynamic DNS service like NoIP to ensure your machine remains reachable even after restarts (given that your ISP will almost always assign you a new dynamic public IP address).使用NoIP等免费动态 DNS 服务也有助于确保您的机器即使在重新启动后仍然可以访问(假设您的 ISP 几乎总是会为您分配一个新的动态公共 IP 地址)。

Once you have that sorted out, ensure that you are not binding your RMI server to localhost or 127.0.0.1 but to 0.0.0.0 .一旦你解决了这个问题,请确保你的 RMI 服务器没有绑定到localhost127.0.0.1而是绑定到0.0.0.0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM