2017-02-12 82 views
0

無法修復此問題3天。 RMI可以在1臺或2臺PC上與localhost或192.168。*正常工作,但遠程客戶端不能使用遠程方法。 啓動rmiregisry,然後綁定服務與Naming.rebind()無法使用RMI遠程方法

註冊表正在創建成功,我可以得到綁定服務的列表,但我甚至不能使用任何方法。

搜索遠程服務與

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

客戶端找到對象,但不能使用它了方法。

下面是代碼: 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:

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(如果需要):

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; 
} 
} 

即時通訊開始用cmd或eclipse進行rmiregistry,然後啓動Sever。 它正確地開始,我不能與本地主機或192.168.0連接* 但IT遠程客戶端不工作 儘量選用.policy文件 - 仍然不起作用

我得到下一個錯誤代碼:

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 

請幫助

+0

可能存在連接問題,如防火牆或其他設置。 嘗試通過telnet從客戶端連接到服務器:telnet server_ip server_port –

+0

'Server'不應該擴展UnicastRemoteObject。 'ServiceServerImpl'不應該創建套接字。 – EJP

+0

@EJP固定..仍然不工作 – shaldnikita

回答

0

您需要:

  1. 設置java.rmi.server.hostname到系統的外部 IP地址,也就是你的路由器的公網IP地址。
  2. 通過super(port)將固定端口號導出遠程對象。
  3. 安排這些端口在路由器端口轉發和1099端口

怎麼辦(3)是路由器的依賴和題外話。

+0

已經完成,隊友 – shaldnikita

+0

如果我在界面中使用超級(端口)impl並且它不適用於它(運行時端口已經在使用) – shaldnikita

+0

因此,使用err另一個端口?如果您的問題中缺少相關事項,則應該解決該問題。 – EJP

0

從您的描述來看,您有一個通用網絡連接問題,它不是特定於RMI的。我的建議是放棄RMI並與netcat或其他通用客戶端/服務器實現一起工作,直到您將連接內容整理出來,然後返回到RMI。

我的猜測是,至少有兩層安全性必須交叉。一個是運行RMI服務器的PC阻塞了所有端口上的連接,或者可能只是一小部分端口。您首先需要在RMI主機上打開端口1099(這是默認的RMI端口,當然您可以選擇其他)。如果你這樣做,你應該能夠從同一本地網絡上的另一臺主機(即在同一個子網192.168.something.something上)連接到RMI主機。

如果您的連接正常工作,那麼下一個跨接橋就是本地網絡上的路由器可能會阻止來自本地網絡之外的流量。請記住,這是一項重要的安全措施。我的建議是避免從外部直接與RMI主機建立連接,因爲這存在安全風險。請嘗試設置SSH隧道,然後使用隧道將外部連接傳輸到RMI主機。 SSH隧道不是太複雜;網絡搜索應該提出一個解釋。

客戶端也可能阻止到端口1099的出站連接;您必須啓用這些連接,或使用SSH隧道來避免此問題。

在早期(大約在1999年),我建立了一個通過RMI進行通信的全球網絡(以及約4個站點)。當時沒有網絡安全的障礙。因此,通過RMI進行遠程通信肯定是可能的,您只需要通過防火牆即可。祝好運並玩得開心點。

+0

它確定與connection.Client找到遠程對象,但不能使用它的方法 – shaldnikita

+0

@shaldnikita連接到註冊表無關。與遠程對象的連接不正常。 – EJP

+0

@EJP它連接到遠程註冊表,但不能調用任何方法 – shaldnikita

0

192.168.X.X是一個私有/ C類IP地址,用於識別本地網絡上的您的機器。要將您的服務展示給他人/互聯網用戶,您需要在路由器上配置端口轉發。它還有助於使用免費的動態DNS服務(如NoIP),以確保即使在重新啓動後您的計算機仍然可以訪問(因爲您的ISP幾乎總是會爲您分配一個新的動態公共IP地址)。

一旦您完成了整理,請確保您沒有將您的RMI服務器綁定到localhost127.0.0.1,而是綁定到0.0.0.0

+0

我已經做了端口轉發 – shaldnikita

+0

我該如何確保? – shaldnikita

+0

@shaldnikita你沒有綁定到127.0.0.1,你不能使用'RMIServerSocketFactory'。這是無關緊要的。 – EJP