As far as I know, RMI uses random ports for communicating between object's stub and remote object. To make things work through firewall, we need to know which ports to open.
Now, isn't it enough to create a stub using UnicastRemoteObject.exportObject(Remote obj, int port)?
According to documentation, it "Exports the remote object to make it available to receive incoming calls, using the particular supplied port."
Does it create a stub that, for any subsequent invocation of remote method, uses this particular port for communication with remote object? If not, then what this port argument does?
Does it create a stub that, for any subsequent invocation of remote method, uses this particular port for communication with remote object?
Yes.
If not, then what this port argument does?
It does that. It also determines what port the remote object is listening on, of course.
Related
I do not quite understand what
UnicastRemoteObject.exportObject(this, 0);
is for. Is it to register an object on rmi server or what. Hope someone can shine me some light.
From Getting Started Using Java RMI
The static method UnicastRemoteObject.exportObject exports the supplied remote object to receive incoming remote method invocations on an anonymous TCP port and returns the stub for the remote object to pass to clients. As a result of the exportObject call, the runtime may begin to listen on a new server socket or may use a shared server socket to accept incoming remote calls for the remote object.
Port 0 means it'll pick a random available port for RMI service port. This might be an issue if you're working in a firewalled/NATted environment which requires you to open a port between Client and RMI server hence instead you can specify something other than 0.
This may seem like a simple question, but I can't find the definite answer:
Say I have three servers on a local un-firewalled network, one of which is the registry (R) and the other two are clients (A and B), and Client A and B both connect to the registry.
Client A obtains a reference to an exported object on B via the registry and invokes a method - does that method call go through the registry? i.e. if A passes a large byte array to B as a parameter to a method call, does that take 2 hops via R, or does the registry tell A that B can be communicated with directly?
No, calls from client to server to not pass through the RMI registry. The registry is only used to look up the reference to the server. Subsequent calls to the server go there directly.
The RMI registry is really nothing more than an RMI server itself, which accepts and stores remote stubs for servers which register with it. It provides a known point-of-entry for clients who don't know where to find the server. It hands the RMI stub back to the client, and the client then talks direct to the server via that stub.
What is RMI registry? What does it do?
Essentially the RMI registry is a place for the server to register services it offers and a place for clients to query for those services. See Introduction to Java RMI. Excerpt:
Figure 1 shows the connections made by the client when using RMI. Firstly, the client must contact an RMI registry, and request the name of the service. Developer B won't know the exact location of the RMI service, but he knows enough to contact Developer A's registry. This will point him in the direction of the service he wants to call..
RMI Registry acts a broker between RMI servers and the clients. The server "registers" its services in the registry - hence a RMI Registry can act as a "directory" for many servers/services. The client does not need to know the location of individual servers, and does a lookup on the RMI Registry for the service it needs. The registry, being a naming directory returns the appropriate handle to the client to invoke methods on.
Google around, there is plenty of info on RMI available.
Java's Remote Method Invocation (RMI) Registry is essentially a directory service.
A remote object registry is a bootstrap naming service that is used by RMI servers on the same host to bind remote objects to names. Clients on local and remote hosts can then look up remote objects and make remote method invocations.(Documentation)
You can use RMI or JNDI to bind and lookup your object remotely with rmi registry.
It's a well know use case of proxy design pattern. RMI servers register objects (essentially stubs) on RMI registry. Remote clients lookup these stubs and invoke methods on it. Behind the scene the method to be invoked, it's arguments are serialized and sent to the actual RMI server which has the implementation. RMI server (skeleton code) deserializes the request invokes actual method, collects results, deserializes it and send it back to the client (stub). Stub deserializes the results and returns it back to the code that invoked this method.
First the server associates a name with a remote object in the RMI registry. When a client wants access to a remote object it looks up the object, by its name, in the registry.
Then the client can invoke methods on the remote object at the server.
http://www8.cs.umu.se/education/examina/Rapporter/471App.pdf
I have a service object that can be connected to via RMI. Currently I'm doing this:
Server
Registry r = LocateRegistry.createRegistry(1234);
r.bind("server", UnicastRemoteObject.exportObject(remoteServer, 0));
Client
RemoteServer s = LocateRegistry.getRegistry("example.com", 1234).lookup("server");
The registry on the server has only one use, to link to the single server object. I figured I might just as well do this on the server:
UnicastRemoteObject.exportObject(remoteServer, 1234);
But then how would I connect to the server object from the client?
The RMI Registry exists to solve the RMI bootstrap problem, which is simply that you can only get a remote stub via a remote method call, and to perform a remote method call you need a remote stub. The Registry reference provided by LocateRegistry.getRegistry() solves this problem (and is used internally by Naming.lookup() if you are using that API). [Note that this stub isn't obtained via a remote method: it is synthethized locally using the host:port you provide. If they aren't correct you won't find out until you use the Registry stub.]
You have several choices to solve the RMI bootstrap problem:
Use the RMI Registry.
Use an LDAP server via JNDI with the LDAP provider.
Use UnicastRemoteObject, serialize the stub obtained when you export the object, and use a shared file, or a socket, or sneakernet, to make the stub available to clients.
Use RMI Activation; serialize the stub obtained when you registered the activatable, and distribute to all clients in a file, along with the client application. From the point of view of stub distribution this is a lot simpler than (3) because the stub remains constant for the life of the application, whereas in (3) you have to redestribute the stub on every export.
You can see that the Registry is certainly the simplest option. Note that you only have to use it to solve the bootstrap problem Once you have a stub, your own application remote methods can return further objects: you don't need more than one remote object in the Registry. You can consider that as a remote object factory.
Not impossible, but not terribly practical because the registry communicates the stub object of the exported object to the client (see http://www.developer.com/print.php/3455311). If you don't have another mechanism for that, you'll be stuck. Use of a registry in distributed systems has other benefits, so I'd actually recommend keeping it for other reasons (location transparency, etc).
Client uses an rmi URL like rmi://localhost:2020/server
see https://stackoverflow.com/a/61210297/503025
Is there a way to determine the ip of the machine on which a remote object is hosted?Is there a way to get this information from the rmi registry?
You can access a rmiregistry only by using the IP it resides. And you can only call methods that are registered with the Remote interface. So writing a function in the interface to return an IP is of no use, I think.
There is no use you can possibly make of the information, so it isn't provided via an API. All you need to do with the stub is call remote methods with it.