I'm very new to RMI and I just decided to give it a try. I got confused by the exportObject(Object, int) method. The documentation says:
Exports the remote object to make it available to receive incoming
calls, using the particular supplied port. The object is exported with
a server socket created using the RMISocketFactory class.
Consider the following simple example:
public interface Client extends Remote {
void clientMethod() throws RemoteException;
}
public class ClientImpl implements Client {
public clientMethod() throws RemoteException {
System.out.println("clientMethod invoked");
}
}
Client stub = (Client) UnicastRemoteObject
.exportObject(new ClientImpl(), 56789); //<------ HERE
So we create a stub and will transfer it to another VM either manually or through RmiRegistry, doesn't matter here.
I'm confused by "[...] the object is exported with a server socket [...]"
What do they mean by that?
A ServerSocket is created to listen for incoming connections at the port you specified when exporting. This port can be shared between multiple remote objects.
The statement about the RMISocketFactory is incorrect. Where did you read that? This class has been obsolete since 1998.
The stub contains the server's hostname or IP address and port number, and some internal data to identify the remote object it belongs to.
TCP connections between the stub and the remote object are created on demand when you call remote methods, via a connection pool.
So, when we transfer the stub to another VM (VM 0), the stub will hold a socket connection to the VM (VM 2) it was originally created on.
No, see above.
The VM 2 in turn will maintain a server socket to accept incoming method invocations.
Correct.
Related
I need:
A client, which communicates with the front-end, which communicates with 3 file servers.
How should I go about doing this? It needs to use RMI as distributed systems.
I also need to monitor all three file servers.
From what I understand, I need to establish an RMI registry, but how do I establish three concurrent servers within one registry?
Okay, so am I right in thinking i'd have the following: A server interface, a server implementation, and a master server which creates the three servers (with unique names) and finally a client?
The 'master server' needs to create a Registry on its own localhost, bind itself to the Registry so the slave servers can find it, and export a remote interface that lets the servers register themselves with it.
The master server must do the binding to this Registry on behalf of the slaves, as you can't bind to a remote Registry. But in fact the slaves don't need to be bound to the Registry at all, only registered with the master.
The master needs to export a second remote interface that provides the API to the client, which provides the upload API and whose implementation performs the balancing act. I would keep this interface separate from the interface used by the slaves, both for security reasons and for simplicity: you don't need clients trying to be slaves, or worrying about what the slave-relevant methods in the remote interface are.
All these servers and registries can run on port 1099.
The slaves are presumably multiple instances of the same service, so they all use a common remote interface. This interface provides the upload-to-slave API, and it also needs to allow each slave to provide the knowledge about how full each slave is, possibly as a return value from the upload method, or else as a query method.
Quick sketch:
public interface UploadMaster extends Remote
{
void upload(String name, byte[] contents) throws IOException, RemoteException;
}
public interface LoadBalancingMaster extends Remote
{
void register(Slave slave) throws RemoteException;
void unregister(Slave slave) throws RemoteException;
}
public interface Slave extends Remote
{
/** #return the number of files now uploaded to this slave. */
int upload(String name, byte[] contents) throws IOException, RemoteException;
int getFileCount() throws RemoteException;
}
I hope this is homework. RMI is a poor choice for file transfer, as it bundles up the entire argument list into memory at both ends, rather than providing a streaming interface.
I am required to make a client-server application as my project submission for university finals.
I have figured out how I would be writing the server but I am kinda confused with this situation I am facing.
So the server is said to support only one defined protocol (represented by a Protocol interface) and would serve to the clients that speaks using that rule only. To test the functionality of the server, I have wrote an implementation that supports the HTTP Protocol so that I can quickly test the server from browser, but there is one thing that is really confusing me.
I have defined the server as:
public interface Server {
// Methods...
public void start() throws Exception;
public Protocol getProtocol();
}
The base implementation of server does this:
public class StandardServer implements Server {
/* Implementations */
public synchronized final void start() throws Exception {
try {
while (true) {
Socket socket = serverSocket.accept();
// Use the protocol to handle the request
getProtocol().handshake(socket);
}
} catch (IOException ex) {
logger.error(ex);
}
}
}
I am confused that is it really required to do this, as I am certain that there are better ways to do this.
What I have considered so far is:
Synchronize the getProtocol() method.
Make the implementation of Protocol a thread and then use it to handle requests.
Spawn a thread when the client connects and pass-in the protocol object to that thread.
What would be the good ways to do this, considering that the server would be getting a decent amount of requests per second?
Any source code help/reference would be highly appreciated.
P.S:
I am not implementing an HTTP Server.
There would be multiple implementations of Server
I am using OkHttp within an application I run on a server, and the server has multiple network interfaces configured at the OS level.
How I can control which network interface OkHttp will to use to send new requests?
By default, I see it simply selects one of the interfaces available, where as I would like to provide users of my application built on top of OkHttp the ability to configure the interface which should be used.
I believe you can use
https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.Builder.html#socketFactory-javax.net.SocketFactory-
public OkHttpClient.Builder socketFactory(SocketFactory socketFactory)
Sets the socket factory used to create connections. OkHttp only uses
the parameterless createSocket() method to create unconnected sockets.
Overriding this method, e. g., allows the socket to be bound to a
specific local address. If unset, the system-wide default socket
factory will be used.
For example https://github.com/yschimke/okurl/blob/e307022667e2beb474309af5b350cd241f2a9045/src/main/kotlin/com/baulsupp/okurl/network/InterfaceSocketFactory.kt
class InterfaceSocketFactory(private val localAddress: InetAddress) : SocketFactory() {
private val systemFactory = getDefault()
override fun createSocket(): Socket {
val s = systemFactory.createSocket()
s.bind(InetSocketAddress(localAddress, 0))
return s
}
If just for testing, you can setup Http proxy with the tool named Charles. Maps the url to the remote interface you want.
I have an RMI client that connects to some RMI server just to let it know it can use this new client.
Can I pass directly some Remote object so that:
serverRemoteObject.registerClient(theClientRemoteObjectTheServerShouldUse);
will actually give the server some object he can use without connecting to my client?
The following question says it is possible, but no real example was given:
Is it possible to use RMI bidirectional between two classes?
Andrew
Yes, you can. This is how exactly callbacks work in case of RMI. You send across an object to the server and when the server invokes a method on your object, it would be executed in the "client" JVM as opposed to on the server. Look into UnicastRemoteObject.export method for export any object which implements the Remote interface as a remote object which can be passed to your server.
interface UpdateListener extends Remote {
public void handleUpdate(Object update) throws RemoteException;
}
class UpdateListenerImpl implements UpdateListener {
public void handleUpdate(Object update) throws RemoteException {
// do something
}
}
//somewhere in your client code
final UpdateListener listener = new UpdateListenerImpl();
UnicastRemoteObject.export(listener);
I'm developing a application using rmi which allow client to login, perform some task and logout. I know that each client is considered as one thread when it call a method on server, however, all clients' threads call to the same object created on server. So now, I want to for each client login successfully, a new thread is created (and a new object, which is used by only one client, is binded, too), a thread terminates when client logout. Hence, each client has its own server's object to work with.
Thank you very much.
Cheers
I know that each client is considered
as one thread when it call a method on
server
That's not correct. The relationship between clients and server threads is undefined in RMI.
In any case you don't need a thread per client. You need a remote object per client. This is a job for the Session pattern:
public interface Login extends Remote
{
Session login(String credentials) throws RemoteException;
}
public interface Session extends Remote
{
// Your API here
}
Have your Login implementation object return a new Session implementation object for every client.