I know that this question has been asked several times but I've yet to find an answer that works for me. Basically I've implemented a client/server solution with RMI. My only problem is that connection to the server is sometimes extremely slow.
When the server is started and a client connects, for the first time, it will take seconds before it gets connected (sometimes it does not even connect but get the ConnectException instead) and after that I will get the Connection refused when trying to communicate with the server.
What makes it even more mind boggling is that it works perfectly fine when I disconnect the first failing client and connect again. The client then connects in under a second and all the communication works flawlessy.
I've tried manually starting the rmiregistry, I've double checked my PATH. I wasn't able to connect to the port with telnet but it works when I play on that port with my Othello game (which is not using RMI). It might be worth to say that I'm doing this on the same network and computer so I'm using localhost.
TL;DR: When I first connect to the server it takes forever, but I'm able to connect. When I then try to communicate with methods it crashes and I receive "java.rmi.ConnectException: Connection refused to host: 192.xxx.xxx.x; nested exception is:
java.net.ConnectException: Connection timed out: connect". If I then close that client and try to connect with another client it takes around one second to connect and then everything works flawlessy. Why is that?
Code for the client:
public class NetworkClient {
private Registry registry;
private IArenaServer server;
public NetworkClient(String ipAddress, int port) throws RemoteException {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
registry = LocateRegistry.getRegistry(ipAddress, port);
server = (IArenaServer)(registry.lookup("arenaServer"));
System.out.println("Client successfully connected to server at " + ipAddress + ":" + "port");
} catch (NotBoundException ex) {
Logger.getLogger(NetworkClient.class.getName()).log(Level.SEVERE, null, ex);
} catch (AccessException ex) {
Logger.getLogger(NetworkClient.class.getName()).log(Level.SEVERE, null, ex);
}
}
Code for the server:
public class ArenaServer extends UnicastRemoteObject implements IArenaServer {
private int port = 9029;
private String ipAddress;
private Registry registry;
public ArenaServer() throws RemoteException {
if(System.getSecurityManager() == null){
System.setSecurityManager(new RMISecurityManager());
}
// try {
//ipAddress = (InetAddress.getLocalHost()).toString();
registry = LocateRegistry.createRegistry(port);
registry.rebind("arenaServer", this);
System.out.println("Server successfully started...");
//System.out.println("Server's IP address is: " + ipAddress);
// } catch (UnknownHostException ex) {
// ErrorHandler.getInstance().reportError("Cannot get IP address", "");
// }
}
Generic example of what I get when trying to communicate with the server after connecting the first time:
java.rmi.ConnectException: Connection refused to host: 192.xxx.xxx.x; 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 $Proxy0.getInstalledGames(Unknown Source)
....
This sounds like a case for java.rmi.server.hostname. See item A.1 in the RMI FAQ, reachable via the RMI Home Page.
Related
Im losing my mind, is there any clear documentation how to run java RMI between host and client remotly? i find in different forums, various puzzle pieces, but never, a from a to z guide, which scurity guidelines have to be followed etc, so that a RMI works. Well, if I run the server and client locally, it works.
Now, my low-level problem is that even if I set the external server address everywhere (?), in the error message it says that "localhost" has refused the connection.... Do you have any ideas?
Client:
try {
System.setProperty("java.rmi.server.hostname","42.155.241.914");
String name = "RemoteBookService";
String serverIP = "42.155.241.914"; // or localhost if client and server on same machine.
int serverPort = 1099;
Registry registry = LocateRegistry.getRegistry(serverIP, serverPort);
IRemoteService rs = (IRemoteService) registry.lookup(name);
Error:
java.rmi.ConnectException: Connection refused to host: localhost;
nested exception is:
java.net.ConnectException: Connection refused: connect
Server:
public static void main(String[] args) throws MalformedURLException, AlreadyBoundException {
try {
System.setProperty("java.rmi.server.hostname","42.155.241.914");
LocateRegistry.createRegistry(1099);
String name="//42.155.241.914/RemoteBookService";
RemoteService rs = new RemoteService();
Naming.bind(name, rs);
System.out.println("Service started");
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("could not start registry");
}
}
At first glance it looks like your server uses LocateRegistry.createRegistry(port); which implies own registry (same process) which you don't store to local variable, and then you call Naming.rebind(bind, rs) which implies use of a local registry (same host, other process) on the default port.
Try changing the lines on server to:
Registry registry = LocateRegistry.createRegistry(port);
...
// NOTE registry.rebind not called with name="//42.155.241.914/RemoteBookService"
registry.rebind("RemoteBookService", stub);
Hopefully this may get you to the next step, but there are plenty of ways this could have gone wrong so you might need to edit the question with more details.
I creating a gRPC server but everything seems to run okay but the server never starts up on the specifies port and application is throwing no errors. But when I test with telnet on that specific port, I get this from terminal
isaack$ telnet localhost 9000
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
telnet: connect to address 127.0.0.1: Connection refused
telnet: Unable to connect to remote host
Below is my code to create the server (NB: All the services are generated okay with proto and the generated code has no errors)
import java.io.File;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.ServerInterceptors;
import io.grpc.ServerServiceDefinition;
public class EmployeeServiceServer {
private Server server;
public static void main(String[] args) {
try {
EmployeeServiceServer service = new EmployeeServiceServer();
service.start();
} catch (Exception e) {
System.err.println(e);
}
}
private void start() throws InterruptedException {
File certificate = new File("/Users/i/certificates/cert.pem");
File key = new File("/Users/i/certificates/key.pem");
final int port = 9000;
EmployeeService employeeService = new EmployeeService();
ServerServiceDefinition serverServiceDefinition = ServerInterceptors.interceptForward(employeeService,
new HeaderServerInterceptor());
server = ServerBuilder.forPort(port).useTransportSecurity(certificate, key).addService(serverServiceDefinition)
.build();
System.out.println("Listening on Port " + port);
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
System.out.println("Shuttin Down Server");
EmployeeServiceServer.this.stop();
}
});
server.awaitTermination();
}
private void stop() {
if (server != null) {
server.isShutdown();
}
}
}
Below is the log from but when I ping it, I get nothing.
Listening on Port 9000
My client is throwing this error as well:
Exception in thread "main" io.grpc.StatusRuntimeException: UNAVAILABLE: io exception
at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:233)
at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:214)
at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:139)
at com.base.services.EmployeeServiceGrpc$EmployeeServiceBlockingStub.getBadgebyNumber(EmployeeServiceGrpc.java:373)
at com.base.client.Client.sendMetaData(Client.java:66)
at com.base.client.Client.main(Client.java:37)
Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: localhost/0:0:0:0:0:0:0:1:9000
You may want to start() your server, as build suggests:
Builds a server using the given parameters.
The returned service will not been started or be bound a port. You will need to start it with Server.start().
Perhaps that server.awaitTermination(); line could become
server.start().awaitTermination();
though I am not entirely sure.
I have faced the same error. The reason being grpc server didn't start.
Server server = ServerBuilder.forPort(port).useTransportSecurity(certificate, key).addService(serverServiceDefinition)
.build().start();
I had written start method as chain to build.
To make it work i had to call start() method separately.
server.start();
This solved the error for me.
PS: I'm writing this answer as the above solution didn't clarify much and had to research alot before finding the solution. Hope this will be helpful for other developers.
I have created a RMI project with server and client. I run the server on my ec2 instance. I had some problems finding out how to run the server property on ec2 in order to accept my windows client. I followed the following steps :
Transfer the files with Filezilla.
Compiled the project as administrator.
I opened the port I still use for my server to my IP address.
The problem I had is that I couldnt connect to my server with the public ip that amazon gives me. So I ran ifconfig and used the private ip.
So inside the code as you will see I used the public amazon ip but when I run it. I run it with the following command
java SkyCorpServer "172.31.31.94" 666 (private ip)(port)
I don't know how but that way the client with the public IP was able to connect.
I have read about the bind and the registry of RMI and how it works (creating a registry and forward it to port. Connect to port and then find the registry and use the Servers stub).
The problem now is that the client connects after 30 secs and when I try to use the remote object (look_op) client crashes with the following message:
java.rmi.ConnectException: Connection refused to host: 172.31.31.94; nested exception is:
java.net.ConnectException: Connection timed out: connect
I have used the default permissions (accept all) because when i tried to do this the Security Manager didn't let me create the registry so I guess that is not the problem (permissions).
Server Code:
private static int port =666;
private static String hostname = "35.167.2xx.xx";
public static void main(String[] args) throws RemoteException {
String bindLocation = "//" + hostname + ":" + port + "/Hello";
System.setProperty("java.rmi.server.hostname",hostname);
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
try { // special exception handler for registry creation
LocateRegistry.createRegistry(port);
System.out.println("java RMI registry created.");
} catch (RemoteException e) {
// do nothing, error means registry already exists
System.out.println("java RMI registry already exists.");
}
SkyCorpServer server = new SkyCorpServer();
try {
Naming.bind(bindLocation, server);
System.out.println("Addition Server is ready at:" + bindLocation);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
System.out.println("Addition Serverfailed: " + e);
}
Server output (running without error)(command i used scroll up) :
java RMI registry created.
SYSTEM: Checking for back-up files. // other staff
SYSTEM: Users file exists. Updating values.
SYSTEM: Checking for back-up files.
SYSTEM: Users file exists. Updating values.
Addition Server is ready at://172.31.31.94:666/Hello
As you can see server listens at 172.31.31.94 port:666
Client Code :
private final static String remoteHostName = "35.167.2xx.xx";
private final static int remotePort = 666;
public SkyCorpClient() throws NotBoundException, MalformedURLException, RemoteException {
String connectLocation = "//" + remoteHostName + ":" + remotePort + "/Hello";
look_op = (ChatInterface) Naming.lookup(connectLocation);
System.out.println("Connecting to client at : " + connectLocation);
}
Client's output (when connected)
Connecting to client at : //35.167.203.111:666/Hello
Connected at : 35.167.203.111
When try to use the remote object look_op :
java.rmi.ConnectException: Connection refused to host: 172.31.31.94; nested exception is:
java.net.ConnectException: Connection timed out: connect
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:619)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:216)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:202)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:130)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:227)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:179)
at com.sun.proxy.$Proxy0.registerUser(Unknown Source)
at SkyCorpClient.actionPerformed(SkyCorpClient.java:206)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.Component.processMouseEvent(Component.java:6533)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
at java.awt.Component.processEvent(Component.java:6298)
at java.awt.Container.processEvent(Container.java:2236)
at java.awt.Component.dispatchEventImpl(Component.java:4889)
at java.awt.Container.dispatchEventImpl(Container.java:2294)
at java.awt.Component.dispatchEvent(Component.java:4711)
My guess is that it connects to public ip 35.xxx and because the server has created the registry to 172.* I can't use the object. Is there something I am missing?
UPDATE:
The problem is, that i'm using a kind of 2-way connection.
On client side, this works:
String a = this.lobby.getMsg();
and this not:
this.lobby.login((Player)UnicastRemoteObject.exportObject(player, 0));
and ideas?
I'm working on a java application which uses RMI for network communication.
On one computer everythings works good, but if i try to run it via the internet i ran into problems.
It seems, that the client is able to retreive the registry from the server and to lookup the lobby-object.
But if the client tries to call the login method of the lobby object via rmi, it takes very long time and i receive the following exception:
Strange thing is, that there is the wrong ip(the client ip) mentioned in this exception.
And if I run a client on the same machine as the server, it works perfectly.
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.ConnectException: Connection refused to host: <client ip(should be server ip?)>; nested exception is:
java.net.ConnectException: Die Wartezeit für die Verbindung ist abgelaufen (=time out)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:353)
at sun.rmi.transport.Transport$1.run(Transport.java:177)
at sun.rmi.transport.Transport$1.run(Transport.java:174)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:553)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:808)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:667)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:273)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:251)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:160)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148)
at $Proxy0.einloggen(Unknown Source)
at Client.login(Client.java:64)
Here is the relevant code:
My server class:
public static final int RMI_PORT = 55555;
public static final String SERVER_IP = "xyz.com";
/**
* Startet Spielserver
*
* #param args
*/
public static void main(String[] args) {
System.out.println("Server starten..");
System.setProperty("java.rmi.server.hostname", SERVER_IP);
try {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
Registry registry = LocateRegistry.getRegistry(SERVER_IP, RMI_PORT);
Lobby lobby = new LobbyImpl();
UnicastRemoteObject.exportObject(lobby, 0);
registry.bind("Lobby", lobby);
} catch (RemoteException e) {
e.printStackTrace();
} catch (AlreadyBoundException e) {
e.printStackTrace();
}
}
Client class:
public Client() {
try {
Registry registry = LocateRegistry.getRegistry("xyz.com", Server.RMI_PORT);
lobby = (Lobby) registry.lookup("Lobby");
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
this.gui = new GUI(this);
}
public void login(String name) throws RemoteException {
Player player = new Player(name);
this.lobby.login((Player)UnicastRemoteObject.exportObject(player, 0));
}
Client startscript:
#!/bin/bash
SCRIPTDIR=$(dirname $0)
java -classpath $SCRIPTDIR/bin Client
Server startscript:
#!/bin/bash
SCRIPTDIR=$(dirname $0)
cd ${SCRIPTDIR}/bin
rmiregistry 55555 &
cd -
java -classpath $SCRIPTDIR/bin -Djava.security.policy=$SCRIPTDIR/src/server.policy -Djava.rmi.server.codebase=file:$SCRIPTDIR/bin/ Server
killall rmiregistry
and last but not least my first (test) policy file:
grant {
permission java.security.AllPermission;
};
what could be the problem?
regards
You need to look at item A.1 of the RMI FAQ on the RMI home page. The problem here is that the wrong IP address is being embedded into the remote stub. So the lookup works, because you are specifying the target IP address yourself in the client, but when you execute the remote method you are relying on the IP address in the stub, which is wrong. The solution is either to correct your /etc/hosts file or to set the system property java.rmi.server.hostname at the server JVM.
The error message is
java.rmi.ConnectException: Connection refused to host: <wrong ip of the server>;
I would check you can ping that server and telnet to the service point.
I have been trying to get a simple networking test program to run with no results.
Server:
import java.io.*;
import java.net.*;
public class ServerTest {
public static void main(String[] args) {
final int PORT_NUMBER = 44827;
while(true) {
try {
//Listen on port
ServerSocket serverSock = new ServerSocket(PORT_NUMBER);
System.out.println("Listening...");
//Get connection
Socket clientSock = serverSock.accept();
System.out.println("Connected client");
//Get input
BufferedReader br = new BufferedReader(new InputStreamReader(clientSock.getInputStream()));
System.out.println(br.readLine());
br.close();
serverSock.close();
clientSock.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
Client:
import java.io.*;
import java.net.*;
public class ClientTest {
public static void main(String[] args) throws IOException {
final int PORT_NUMBER = 44827;
final String HOSTNAME = "xx.xx.xx.xx";
//Attempt to connect
try {
Socket sock = new Socket(HOSTNAME, PORT_NUMBER);
PrintWriter out = new PrintWriter(sock.getOutputStream(), true);
//Output
out.println("Test");
out.flush();
out.close();
sock.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
The program works just fine when I use 127.0.0.1 or my internal IP for the hostname. But whenever I switch to my external IP address, it throws a java.net.ConnectException: Connection refused: connect error.
I purposely picked such an uncommon port to see if that was the problem, with no luck.
I can connect with no problems using telnet, but when I try to access the port with canyouseeme.org, it tells me the connection timed out.
I even tried to disable all firewalls and antivirus including the Windows default ones and the router firewall, with all ports forwarded and DMZ enabled, and it still says that the connection timed out. I use Comcast as my ISP, and I doubt that they block such a random port.
When I use a packet tracer, it shows TCP traffic with my computer sending SYN and receiving RST/ACK, so it looks like a standard blocked port, and no other suspicious packet traffic was going on.
I have no idea what is going on at this point; I have pretty much tried every trick I know. If anyone know why the port might be blocked, or at least some way to make the program work, it would be very helpful.
These problem comes under the following situations:
Client and Server, either or both of them are not in network.
Server is not running.
Server is running but not listening on port, client is trying to connect.
Firewall is not permitted for host-port combination.
Host Port combination is incorrect.
Incorrect protocol in Connecting String.
How to solve the problem:
First you ping destination server. If that is pinging properly,
then the client and server are both in network.
Try connected to server host and port using telnet. If you are
able to connect with it, then you're making some mistakes in the client code.
For what it's worth, your code works fine on my system.
I hate to say it, but it sounds like a firewall issue (which I know you've already triple-checked) or a Comcast issue, which is more possible than you might think. I'd test your ISP.
Likely the server socket is only being bound to the localhost address. You can bind it to a specific IP address using the 3-argument form of the constructor.
I assume you are using a Router to connect to Internet. You should do Port Forwarding to let public access your internal network. Have a look at How do you get Java sockets working with public IPs?
I have also written a blog post about Port forwarding, you might wanna have a look :) http://happycoders.wordpress.com/2010/10/03/how-to-setup-a-web-server-by-yourself/
But I still couldn't get this accessed over public IP, working on it now...
I had the same problem because sometimes the client started before server and, when he tried to set up the connection, it couldn't find a running server.
My first (not so elegant) solution was to stop the client for a while using the sleep method:
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
I use this code just before the client connection, in your example, just before Socket sock = new Socket(HOSTNAME, PORT_NUMBER);
My second solution was based on this answer. Basically I created a method in the client class, this method tries to connect to the server and, if the connection fails, it waits two seconds before retry.
This is my method:
private Socket createClientSocket(String clientName, int port){
boolean scanning = true;
Socket socket = null;
int numberOfTry = 0;
while (scanning && numberOfTry < 10){
numberOfTry++;
try {
socket = new Socket(clientName, port);
scanning = false;
} catch (IOException e) {
try {
Thread.sleep(2000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
return socket;
}
As you can see this method tries to create a socket for ten times, then returns a null value for socket, so be carefull and check the result.
Your code should become:
Socket sock = createClientSocket(HOSTNAME, PORT_NUMBER);
if(null == sock){ //log error... }
This solution helped me, I hope it helps you as well. ;-)