I have a client server structure. The server exposes a service with RMI, let's say it is: RemoteInterfaceA. The service is regualary exported using UnicastRemoteObject.exportObject(service, port) and bound in the RMI Registry.
The server however must update something in the client so also the client creates a RemoteInterfaceB, it exports it using UnicastRemoteObject.exportObject(update, port). It cannot however create a Registry (because unlike the server it is not reachable from the internet). To give to the server its update stub, I pass the update as an argument of a service (RemoteInterfaceA) method.
Will it work?
It will work, firewalls permitting. As you say the client isn't reachable from the Internet, it won't for you. The server will get a NetworkUnreachableException or a connect timeout when it tries to callback the client.
Related
I am following the Java RMI tutorial from here to build an example compute engine where the clients can submit tasks to a known server, and which the server will perform the task and return the result.
Having compiled and created new tasks sucessfully I want to learn further by reversing the logic, i.e. the server sends the task to the clients.
How would I conceptually do this? If I have understood correctly, the RMI server exposes the executeTask() method, which a client calls upon connecting to the server. I am toiling with turning each client into a 'server', each running an RMI registry and another application will connect to each of the rmi registries and call the executeTask method, and thus download the class.
Is there an obvious apporach in the logic I am missing? Having multiple RMI registries seem's incorrect.
What I want to end up with is a server with exposed RMI registry. All clients connect to server, server calls executeTask() method on each client to process the task on the clients. Ofcourse the task class needs to be located at the server and downloaded dynamically to the clients (currently the task is located at the client and sent to the server).
Have the server expose a fetchNextTask() method, and have the clients call it when they're ready to perform another task.
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 something like a proxy server (written in java) running between my clients and the actual video server (made in c++). Everything the clients send goes through this proxy and is then redirected to the server.
It is working fine, but I have some issues and think it would be better if I could make this proxy server only to listen to the clients requests and then somehow tell the server that a request has been made from the client side, and that it is supposed to create a connection with the client directly.
Basically in the TCP level what I want to happen is something like this:
1- whenever a client sends a SYN to my proxy, the proxy just sends a message to the real server telling the ip and port of the client.
2- The server would then send the corresponding SYN-ACK to the specified client creating a direct connection between client and server.
The proxy would then be just relaying the initial requests (but not the later data transfer) to the actual server. I just don't know if that is possible.
Thank you very much
Nelson R. Perez
That's very much the way some games (and Fog Creek CoPilot) do it, but it requires support on both the server and the client. Basically the proxy has to say to the client and server "try communicating with the directly on this ip and this port" and if they can't get through (because one or both is behind a NAT or firewall), they fall back to going through the proxy.
I found this good description of "peer to peer tcp hole punching" at http://www.brynosaurus.com/pub/net/p2pnat/
Does the proxy and server lives on the same machine? If so, you can pass the connection to the server using Socket Transfer or File Descriptor Passing. You can find examples in C here,
http://www.wsinnovations.com/softeng/articles/uds.html
If they are on the different machines, there is no way to pass connection to the server. However, it's possible to proxy the IP packets to server using VIP (Virtual IP). This is below socket so you have to use Link layer interface, like DLPI.
You don't have control of TCP handshake in userland like that. This is what firewalls/routers do but it all happens in the kernel. Take a look at the firewalling software for your platform - you might not even have to code anything.