I have a JMX enabled application which creates RMI Registry by doing:
rmiRegistry = LocateRegistry.createRegistry(registryPort);
and then later on it creates JMXConnectorServer by doing:
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi://localhost:" + serverPort
+ "/jndi/rmi://:" + registryPort + "/jmxrmi");
connector = JMXConnectorServerFactory.newJMXConnectorServer(
url,
null,
ManagementFactory.getPlatformMBeanServer());
connector.start();
My problem is that I cannot connect to this JMX Server from a remote host using JConsole. I've followed the instructions for debugging/tracing JConsole and I can see that the problem is that JConsole tries to connect to a bogus IP address that it must have gotten from the Registry. Ok, it isn't exactly bogus because it happens to correspond to a virtual network interface I have on the JMX Server host machine. How on earth does JMX pick that up?
A netstat on my application reveals that both the serverPort and the registryPort are bound on the wildcard interface (on both IP4 and IP6) which is as expected since I haven't supplied socket factories. Basic connectivity works from the remote host, i.e. I can get the telnet test to pass on both ports.
I would have assumed that I would have to change 'localhost' in the JMXServiceURL to the name of my host (as other hosts sees it, not how it sees itself) but that doesn't help.
What do do ?
UPDATE1
After some more investigation I'm pretty sure this 'bogus IP address' comes because RMI just picks the first IP it finds on its own host and then uses that as its 'call-me-back' address. It then happens to find that virtual NIC that exists on this host. That's really not want I want. I want to be able to control explicitly the RMI 'call-me-back' address.
Welcome to RMI hell.
The end point resolve himself and send back to jconsole the ip to use.
If you can try to use JMXMP : http://meteatamel.wordpress.com/2012/02/13/jmx-rmi-vs-jmxmp/.
You can also try java.rmi.server.hostname :
http://docs.oracle.com/javase/7/docs/platform/rmi/spec/rmi-properties2.html
Related
I am testing on java.net.ServerSocket.
What I want is the following.
When connecting to aaa.com, you get aaa.com,
Getting bbb.com when connecting to bbb.com.
My etc/hosts file configuration is as follows.
127.0.0.1 aaa.com
127.0.0.1 bbb.com
I used the following java source.
ServerSocket server = new ServerSocket(port);
Socket request = server.accept();
request.getInetAddress().getHostName();
And when connecting to aaa.com, aaa.com is returned.
When connecting to bbb.com, aaa.com is returned.
How can I get bbb.com when connected to bbb.com?
This code is not connecting to anything. It is accepting connections from ... something.
So ... I presume that you have some client code (not shown) that is connecting to port port using hostnames "aaa.com" and "bbb.com" respectively. And you want this server side to know which hostname that the client side used.
It is not possible.
The client resolves the hostnames to an IP address and then makes the connection using the IP address (and only the IP address). Since the IP address is the same in both cases, the server side cannot distinguish the two cases.
It follows that if the application level of the server needs to know the hostname that the client used to make the connection, then the application protocol must pass this information from the client to the server. (That is what protocols like HTTP, FTP and so on do.)
I'm working on a project using Java RMI and with a client-server implementation.
On the server side, this is how I initialize my server:
final String url = "localhost";
final int port = 8090;
LocateRegistry.createRegistry(port);
IServerGame serverGame = new ServerGame();
Naming.rebind("//"+url+":"+port+"/undercover", serverGame);
System.out.println("Server running at //" + url + ":" + port + "/undercover")
Undercover is the name of my application. We chose to use the port 8090
arbitrarily.
Now, here is how I initialize the connection client-side:
try {
server = (IServerGame) Naming.lookup("//"+address+":8090/undercover");
System.out.println("Connected to server " + address + ".");
} catch (Exception e) {
System.out.println("Connection failed.");
e.printStackTrace();
}
address is a string in the parameter of the method which initializes the connection and is the IP of the server. We ask the client to enter this IP to allow us to connect to different servers if we want.
When I run my application in local, whether I use localhost or my private IP 192.168.x.x as address, everything works fine. The client connects to the server and I can use the application. The problem is that when I want to use the application via WAN, sending the client to a friend and starting the server on my local machine, it doesn't work anymore. I get this error:
java.rmi.ConnectException: Connection refused to host: (private IP of host machine); nested exception is:
java.net.ConnectException: Connection timed out: connect
I've already checked a lot of posts in StackOverflow with the exact same problem and the usual answer is to either set the SystemProperty(java.rmi.server.hostname,"192.168.x.x") or do it via the -Djava.rmi.server.hostname in command line. I'm using Gradle to compile. I run the application via the run task. The client is a basic fx application too. None of this works unfortunately. I've also tried to open the port 8090 in my firewall but it doesn't solve the problem either.
Now maybe I'm doing this wrong. I've also tried to replace my private IP 192.168.x.x, which is IPv4 that I found via ipconfig in the command shell, with my public IP 79.95.x.x. But, again, it doesn't work.
I tried adding the SystemProperty(java.rmi.server.hostname,"192.168.x.x") like the first line of code that appears in the server code I showed you above.
I'm connected to internet via 4G. I don't have a box connection, so I can't really go to the box settings to allow certain ports, if that's ever a thing that could fix the issue.
EDIT :
So i've tried to switch from naming implementation in server-side to Registry implementation as it was suggested bellow but it didn't make any difference. As i thought it could be just a connection problem, i asked a friend to ping the server with telnet on the port 8090 and in fact it didn't work. He ran telnet [domain name or ip] [port] and the error was :
Unable to connect to remote host: Connection timed out
So the problem is that the external clients cannot reach my server or connect to the port. As i'm using 4G as internet connection as i mentioned above, any idea on how i could make the port reachable ?
Try using class java.rmi.registry.Registry rather than class java.rmi.Naming.
On the server side:
final int port = 8090;
Registry registry = LocateRegistry.createRegistry(port);
ServerGame serverGame = new ServerGame();
IServerGame stub = (IServerGame) UnicastRemoteObject.exportObject(serverGame, 0);
registry.bind("undercover", stub);
On the client side:
Registry registry = LocateRegistry.getRegistry("server host name or IP", 8090);
IServerGame serverGame = (IServerGame) registry.lookup("undercover");
I've looked online, and everything I find shows how to make a separate server to connect to the main server if it's behind a nat or firewall.
But in my case the client is behind the NAT, and the server is on the local network.
So it's set up kinda like below:
Client Actual:10.0.0.1 -> Client NAT:100.0.0.2:1111 <--> Server 10.0.0.0:1099
The Java code I use to connect to the server is as below:
String serviceUrl = "service:jmx:rmi:///jndi/rmi://10.0.0.0:1099/jmxrmi";
String[] credentials = new String[] {"username", "password"};
String objectName = "org.apache.activemq:type=Broker,brokerName=test";
JMXServiceURL url = new JMXServiceURL(serviceUrl);
Map<String, String[]> env = new HashMap<String, String[]>();
env.put(JMXConnector.CREDENTIALS, credentials);
JMXConnector jmxc = JMXConnectorFactory.connect(url, env);
conn = jmxc.getMBeanServerConnection();
broker = MBeanServerInvocationHandler.newProxyInstance(conn, new ObjectName(objectName), BrokerViewMBean.class, true);
And the error it throws is:
java.rmi.ConnectException: Connection refused to host: 10.0.0.0; nested exception is:
java.net.ConnectException: Connection timed out: connect
So my question is, how do I make this client behind NAT connection work?
First of all: there is nothing special in with regard with network configuration for ActiveMQ to work. ActiveMQ's protocol is single port, and can be easily routed just like most other TCP/IP protocol.
Therefore, given that the server is properly listening on its TCP port and that a client can successfully connect to it locally, then this problem can be analyzed as if it was any other network-related problem.
Can the client machine ping the server machine? It is difficult from the IP address scheme that you present to properly understand your network, but as it is presented right now, the client machine will simply assume that the server is on the local network and therefore send an ARP request asking for the MAC address of "10.0.0.0" (which will timeout because there is no such machine to answer the request) rather than forward the request to its NAT gateway. If that is indeed the problem you have, then there are three possible solutions: a) modify the network layout (have the client use a different IP scheme), b) setup a static route for the server's IP on the client machine to force its routing through the gateway, or c) add a port redirect on the gateway and have the client connect to the IP address of the gateway instead. Now solution a is not very practical, unless your setup is barely a lab configuration. Solution b is a possibility, but a really bad one. Solution C, that is setting up port redirection on the gateway, is the most common solution to this kind of problem.
Use hostnames on both sides, by setting the same -Djava.rmi.server.hostname=XXX. Be sure that hostname is resolvable on both sides. You can have a look at http://docs.oracle.com/javase/8/docs/technotes/guides/rmi/faq.html#nethostname
I have a java process running (on java 7) on some remote server that I want to monitor using Java Mission Control. However, JMC is unable to connect, although I can telnet to the server using the port jmx remote port (12345 here, see below).
The remote java proces is started with
-Dcom.sun.management.jmxremote=true
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.port=12345
-Djava.rmi.server.hostname=<some ip address>
-Dcom.sun.management.jmxremote.authenticate=false
and these seem to be correct values to me. Port 12345 has been opened on the firewall, but I suspect that the rmi server port is blocked by the firewall.
Thus, my question is: Is there any way (using netstat on the server or maybe even telnet from the client) to determine which rmi server port the java process is currently using on the server? (Using netstat, I see several ports being used by the java process. However, I don't have a clue which one is the rmi port.)
Adding '-Dcom.sun.management.jmxremote.rmi.port=12345' could help
See Why Java opens 3 ports when JMX is configured?
This should display where a JMX remote client is told to connect to (plus some internal info) possibly after timing out:
//nopackage -- move if you like
import java.rmi.Remote;
import java.rmi.registry.*;
import java.rmi.server.*;
import sun.rmi.server.UnicastRef;
import sun.rmi.transport.LiveRef;
public class JMXTarget {
/*
* run: java JMXTarget host port
* where host (name or address) contains the JVM process offering JMX
* and port (number) is the registry specified by -Dcom.sun.management.jmxremote.port
*/
public static void main(String[] args) throws Exception {
Registry reg = LocateRegistry.getRegistry (args[0], Integer.parseInt(args[1]));
Remote r = reg.lookup ("jmxrmi");
RemoteObject ro = (RemoteObject)r;
RemoteRef rr = ro.getRef();
UnicastRef ur = (UnicastRef)rr;
LiveRef lr = ur.getLiveRef();
System.out.println (lr);
}
}
Note if sysprop java.rmi.server.hostname is specified as you did, its value (your "some ip address") is where the client connects. If that value is not an address of the target machine, or a name that resolves (for the client) to an address of the target machine, it won't connect. If you don't specify it, it defaults to (edit) the value determined by InetAddress.getLocalHost() which is or at least should be a valid address for that machine.
I am having trouble connecting my online application to others across another network. I am able to give them the hostAddress to connect when we are on the same network but when we are doing it across the internet the generated host address doesn't allow a connection, nor does using the ip address gotten from online sites such as whatismyip.com
My biggest issue isn't debugging this code, because it works over intra-network but The server doesn't see attempts when we try to move to different networks. Also, the test port I am using is 2222.
InetAddress addr = InetAddress.getLocalHost();
String hostname = addr.getHostName();
System.out.println("Hostname: " + hostname);
System.out.println("IP: " + addr.getHostAddress());
I display the host to the server when it is starting
if (isClient) {
System.out.println("Client Starting..");
clientSocket = new Socket(host, port_number);
} else {
System.out.println("Server Starting..");
echoServer = new ServerSocket(port_number);
clientSocket = echoServer.accept();
System.out.println("Warning, Incoming Game..");
}
If it works on your local lan but not across the internet then one or both peers are probably on a NAT'ed connection, meaning that the public IP address you see on the internet is not the same as the IP address of the machine you are trying to talk to. You would probably need to set up some kind of port forwarding to allow your app to connect.
The issue is probably firewall configuration.
Assuming you're testing this at home (it would usually be more complex from a university or company).
Usually you'll need to configure your router to let port 2222 open (you can also open port 5555 and tell your router to redirect to the host you want on your lan (there might be many), and port 2222).
To sum up:
other user ----> internet ----> [your modem] internet_IP -> [your router] lan_IP -> your computer lan_IP2
internet_IP is given by your ISP; find it here: http://www.whatismyip.com/
lan_IP: you defined in your router configuration. Typically: 192.168.0.1
lan_IP2: usually given to your PC by the router (DHCP). Find it by typing ipconfig (Windows) or ifconfig (Linux).
You need to tell your router to open port 2222, and route it to lan_IP2 on port 2222.
Configuring the router is usually done by connecting on its http interface: http://192.168.0.1
Some additional information might be helpful. Can you ping the machine from where you are? Are you attempting to go through a firewall? You say they work over localhost or local network - those are a bit different. Do you mean a network using local space (i.e. 10...* or 192.168.. or the like)? You say you are using a test ip of 2222 - that is not an ip address. Is that the domain of the address? Or is that the port number?