when I call a method from a RMI Ubuntu client on the OSX server passing an UnicastRemoteObject as parameter, things are super slow. So slow, that eventually, it gets executed but more likely, I get timeout exceptions after like 2-3 minutes. Both machines are in the same network. It's a freshly installed Ubuntu 12.04. I can telnet from the Ubuntu machine to the OSX one on the used RMI port, so at this point, it doesn't seem to be a problem. I can also call methods on the server without this UnicastRemoteObject parameter and everything works fine. From OSX to OSX is also fine...
This is, how the server gets started:
LocateRegistry.createRegistry(port);
nodeManager = new NodeManagerImpl(maxConfigurationsPerNode, true);
Registry registry = LocateRegistry.getRegistry(host, port);
registry.rebind("NodeManager", nodeManager);
And this is, how the client connects and calls the method:
Registry registry = LocateRegistry.getRegistry(host, port);
nodeManager = (NodeManager) registry.lookup("NodeManager");
handler = new NodeHandlerImpl();
id = nodeManager.register(handler, id);
NodeHandlerImpl is basically this:
public class NodeHandlerImpl extends UnicastRemoteObject implements NodeHandler {
public NodeHandlerImpl(boolean noSSL) throws RemoteException {
super(0, null, null);
}
....
}
The call to "register" is the one taking ages... NodeHandler extends Remote. When I remove the parameter handler, everything works fine again...
I'm a bit stuck here since a few hours, any clue would be great.
// Edit: Yep, Reverse DNS was the error.
With this hint, I found this site:
http://www.communardo.de/home/techblog/2008/09/17/rmi-kommunikation-zu-remote-hosts-mit-unguenstiger-dns-konfiguration/
So I changed my client connect code to the following and everything was fine:
System.setProperty("java.rmi.server.hostname", host);
Registry registry = LocateRegistry.getRegistry(host, port);
nodeManager = (NodeManager) registry.lookup("NodeManager");
handler = new NodeHandlerImpl();
id = nodeManager.register(handler, id);
This is most likely DNS misconfiguration. Java uses both DNS and reverse DNS. Make sure both are working correctly at both client and server hosts when looking up the other.
Related
I have a standalone zookeeper server running.
client = CuratorFrameworkFactory.newClient(zkHostPorts, retryPolicy);
client.start();
assertThat(client.checkExists().forPath("/")).isNotNull(); // working
listener = new LeaderSelectorListenerAdapter() {
#Override
public void takeLeadership(CuratorFramework client) throws Exception {
System.out.println("This method is never called! :( ");
Thread.sleep(5000);
}
};
String path = "/somepath";
leaderSelector = new LeaderSelector(client, path, listener);
leaderSelector.autoRequeue();
leaderSelector.start();
I am connecting to the server successfully, defining a listener and starting leader election.
Note: There is only 1 client.
But my client app is never taking leadership. I am not able to figure out what I am doing wrong. Also this is a trivial single client scenario. Shouldn't the client already be a leader
EDIT:
It works if I use TestingServer from curator-test library instead of starting my Zookeeper server, like below -
TestingServer server = new TestingServer();
client = CuratorFrameworkFactory.newClient(server.getConnectString(), retryPolicy);
...
Does this mean there is something wrong with my zookeeper server.
This is my zoo.cfg -
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper/ex1
clientPort=2181
Also, the server appears to be working fine as I am able to connect to it using cli and am able to create/delete zNodes.
I'm working on a personal project for school where I have to user RMI to communicate between server and client.
Project info
The goal of my project is to retrieve stock info (from NYSE) for each day on the server at a specific time (after NYSE is closed). Each stock object is saved in a database. The information is retrieved over http and has nothing to do with RMI.
For the client it is also possible to fetch the stocks. When a user wants to fetch the stock object for the current day, it is directly fetched from the 3th party service. When a user, for example, wants to fetch Google's stock from last month, it is requested on the server over RMI. The server will the look for the stock object in the database and retrieve a Stock object and send it to the client.
Problem
When I start the client application, I have to login. The client will create a User object containing the username and password.
When I press the login button, it will take around 2 minutes before the main screen will be shown.
Below the source code where I setup the RMI connection.
Server (main.java)
public static void main(String[] args) throws UnknownHostException {
InetAddress IP= InetAddress.getLocalHost();
System.out.println("IP of my system is := "+IP.getHostAddress());
if(args.length == 1 && args[0].toLowerCase().equals("local")) {
System.out.println("Running on localhost");
System.setProperty("java.rmi.server.hostname", IP.getHostAddress());
} else {
System.out.println("rmi hostname is set to 37.97.223.70");
System.setProperty("java.rmi.server.hostname", "37.97.223.70");
}
try {
Registry reg = LocateRegistry.createRegistry(1099);
StockAppServer server = StockAppServer.getInstance();
reg.rebind("StockApp", server);
System.out.println("StockApp bound for StockAppServer object.");
} catch (RemoteException e) {
e.printStackTrace();
}
}
Based on the arguments that are passed to the application when it starts, I set the RMI hostname to my current IP address, or to the remote server address. The remote server address is a static IP, so this won't change.
Server (StockAppServer.java)
This class implements the interfaces that is used by the client to call methods on the server. So this class extends UnicastRemoteObject. When I start the server, registerStockTask() will be called. This method will fetch the ticker symbols (What are ticker symbols?) and then schedule a task to fetch all stock objects at a specific time.
private static StockAppServer _instance;
private List<User> loggedInUsers;
private List<Group> activeGroups;
private List<Notification> registeredNotifications;
private StockAppServer() throws IOException {
_instance = this;
this.loggedInUsers = new ArrayList<>();
this.activeGroups = new ArrayList<>();
this.registeredNotifications = new ArrayList<>();
this.registerStockTask();
clearActiveGroups();
checkForCompletedNotifications();
// Start the restful framework to allow incoming connections from the NodeJS server to manage new notification
Router.getInstance();
}
public static StockAppServer getInstance() {
try{
return _instance == null ? new StockAppServer() : _instance;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Client (main.java)
public static void main(String[] arguments) throws Exception {
args = arguments;
Application.launch();
}
#Override
public void start(Stage primaryStage) throws Exception {
InetAddress IP= InetAddress.getLocalHost();
System.out.println("IP of my system is := "+IP.getHostAddress());
if(args.length == 1 && args[0].toLowerCase().equals("local")) {
// Program started with local command, expect that server is running on local host
reg = LocateRegistry.getRegistry(IP.getHostAddress(), 1099);
System.out.println("Attempting to connect to RMI server over 127.0.0.1");
} else {
// Program started without additional commands. Except that "the server" is available;
reg = LocateRegistry.getRegistry("37.97.223.70", 1099);
System.out.println("Attempting to connect to RMI server over 37.97.223.70");
}
try {
StockApp.getInstance().setServerInterfaces((IStockSend) reg.lookup("StockApp"), (IUserHandling) reg.lookup("StockApp"));
} catch(RemoteException e) {
AlertMessage.showException("Unable to connect to server.", e);
} catch (NotBoundException e) {
AlertMessage.showException("No server has been found with the name \"StockApp\" on the remote host.\nPlease try again later", e);
}
LoginController.showMenu();
//FileNotFoundException e = new FileNotFoundException("Couldn't find file blabla.txt");
//AlertMessage.showException("Something went wrong. Please try again later.", e);
}
How I tried to solve my problem
When I test my applications local, there is no problem. The login method will be finished within a few milliseconds and I will be represented the main screen.
I started by turning of my firewall on my macbook. No result, login method still takes around 2 seconds.
I turned off the firewall om my Ubuntu server. No result, both firewalls on server and macbook are turned off. Login method still takes around 2 seconds.
On the server runs (thanks to jenkins) another (unrelated) program. This program uses sockets instead of RMI. When this program is not running, the login method still takes around 2 minutes.
In StockAppServer.java, I called the following method:
super(1099);
This has the same outcome as the above steps I took.
I don't know what else I can try to solve my problem.
I tried to give as much code as possible for the RMI part. I you need any other source code, just ask and I can update this question. Also, the source code is available via github: https://github.com/juleskreutzer/GSO-Maatwerk. Make sure to run the program with -remote param.
Update 1 (9-1-2017)
As yanys requested in the comments, I should run the following command:
dscacheutil -q host -a name localhost
this returns the following output:
Mac:
name: localhost
ip_address: 127.0.0.1
Ubuntu:
dscacheutil: command not found
Update 2 (9-1-2017)
I checked with the provider of my VPS where I run the java server on. On their side everything should be OK. According to them, it shouldn't be a dns problem. After some research, I found out that RMI uses both DNS and reverse DNS. It this case, reverse DNS was the issue. Please see my answer on how I solved my problem.
As EJP pointed out in the comments on the question, it was an DNS problem.
I contacted the support of my hosting provider to see if I had some wrong settings. They helped me a lot in solving this problem.
First we tested the speed of my VPS, this is around 1000mbit download and upload speed. After we checked this, they said there was nothing wrong on their side.
After doing some research, I found out that RMI uses both DNS and Reverse DNS. The problem was that I didn't setup the reverse DNS on my server. I already have a domain name to use for reverse DNS.
I than did the following:
Create a A-record on my website that points to the IP address of the server. I named it vps.mydomain.com
Add the reverse DNS in the control panel of my server
Change the hostname of my server to vps.mydomain.com*
*My server runs Ubuntu 16.04, on ubuntu machines with systemd, you can use the command
sudo hostnamectl set-hostname new-name
to change the hostname
I have an RMI server which publishes an object like so:
int port = ....;
String name = "...";
Remote server = UnicastRemoteObject.exportObject(someobject, port+1);
Registry registry = LocateRegistry.createRegistry(port);
registry.rebind(name, server);
log.info("created service name "+name+", on port "+(port+1)
+" in registry on port "+port);
When I stop the program and just rerun it, it logs that it has created everything, but then immediately exits, likely due to the rmi server thread exiting (the last non-daemon). I registered a defaultUncaughtExceptionHandler, but get nothing logged from it. Only after a minute or so I am able to restart the program without it immediately exiting.
If I would always use the same port, this would only half surprise me, because I know that ports may be blocked a little while after their last use. But the behavior is the same even if I use a different port (+100 or so) each time.
Any ideas why this happens and how to possible prevent it?
You need to store the result of createRegistry() into a static variable. Otherwise it is liable to be garbage-collected.
I have the following code for custom syslog server (using Syslog4J) which works on Windows.
final UDPNetSyslogServerConfig udpConfig = new UDPNetSyslogServerConfig();
udpConfig.setPort(Integer.parseInt(port));
udpConfig.setHost(host);
udpConfig.addEventHandler(new Handler());
udpConfig.setUseDaemonThread(false);
SyslogServerIF server = SyslogServer.createInstance(host + port, udpConfig);
server.run();
It listens for the incoming events and invokes handler (method) whenever the event is received.
If I run the same code on Mac, it just comes out. Even if I use a loop to wait for the events, the events are not captured.
while (!stop) {
SyslogUtility.sleep(1000);
}
Even the handler's initialize() method is not invoked on Mac.
What port are you trying to use on Mac?
Is it in conflict with an in-use port (default is 514)?
Check /etc/syslog.conf on MacOS to see what port it is using for the built in syslog. On Ubuntu, this can be found in /etc/rsyslog.conf.
Using RMI to pass String object from WebAppA to WebAppB.WebAppB is the RMIServer whereas WebAppA is RMIClient.I have added ContextListener in WebAppB, so that the rmi service starts right away when the context is initialized in tomcat.And in the contextDestroyed method of tomcat I am trying to close/shut down rmi using the following statements:
unexportObject(remoteObj,true);
LocateRegistry.getRegistry(3232).unbind("MessagePath"); //MessagePath - name of the remote reference
But even after the execution of the aforeseen statements, rmi is listening for incoming requests at port 3232.I saw that by using "netsat -ano" in command prompt.Please do help me to close RMI Service.
getRegistry returns a stub only, so use the instance returned by createRegistry in unexportObject. However in my case this does not help either - the registry is not active anymore, but the sockets are still open and listening :-(
createRegistry won't work when you're trying to shutdown the registry.
Registry registry = LocateRegistry.createRegistry(3232);
This will throw a BindException when the registry is already running. So you cannot the create object to use it in
UnicastRemoteObject.unexportObject(registry, true);
However, even if you use
Registry registry = LocateRegistry.getRegistry(3232);
You just get the stub, which cannot be used as a parameter to unexport the object.
The reason its a cause of concern for me is because I only wish to start the registry if I could check it has not started yet. And I haven't found a way to do that!
I have found a way of shutting down the registry from any process (and for that matter shutting down any bound processes which are bound in the registry)
Any of the Interfaces which extends remote and which you eventually want to kill off should also extend the following Interface:
public interface PIDSupplierInterface extends Remote {
String getPID() throws RemoteException;
}
every server class you create with this as part of its interface must then implement getPID(). The thing you then have to do is return the process ID. Google "getpids" for Windows, or go here: www.jroller.com/santhosh/entry/get_current_java_process_id. For Linux as I understand it getting the PID is more straightforward. Then (in Windows) you want to go
String PID = myServer.getPID();
String[] a_command = { "taskkill", "/pid", PID };
Runtime.getRuntime().exec(a_command, envp, dir);
to kill off the PID of the registry itself, first, when starting the registry (programatically), simply go
PIDSupplierInterface stub = PIDSupplierInterface)UnicastRemoteObject.exportObject(
new PIDSupplierServer(), 0);
reg.bind( "regKiller", stub );
where PIDSupplierServer is a class which implements only PIDSupplierInterface.
Then, when you want to kill off the RMI registry from any Process just go
PIDSupplierInterface regProcess = (PIDSupplierInterface)reg.lookup( "regKiller" );
String regPID = regProcess.getPID();
String[] a_command = { "taskkill", "/pid", regPID };
Runtime.getRuntime().exec(a_command, envp, dir);
the reg has disappeared from your system. Or is your question more complicated for some reason? Any comments welcome.