A very simple way to let two Java applications (a server and a client) talk to each other, especially on the same machine, is to use Remote Method Invocation (RMI). RMI allows to share Objects between Java applications which means, it is a very high level abstraction of communication and removes the necessity to write custom network code or handle the involved concurrency.
Here is a very basic example:
Step 1: Create a common Interface
Create a common interface that describes the functionality provided by th server:
package com.example.remote;
import java.io.Serializable;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteControlInterface extends Remote, Serializable {
public void sendCommand(String command) throws RemoteException;
}
This interface must extend java.rmi.Remote
and java.io.Serializable
and every methot must be able to throw a java.rmi.RemoteException
. Put this in a library and use this library in the server and the client as well. How this is accomplished, depends on the IDE you're using. The simplest way is probably to put server, client and the common library in the same project.
Step 2: Create the server application
Create an implementation of the common interface in the server application:
package com.example.remote.server;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import com.example.remote.RemoteControlInterface;
public class RemoteControl extends UnicastRemoteObject implements RemoteControlInterface {
private static final long serialVersionUID = 1L;
protected RemoteControl() throws RemoteException {
}
@Override
public void sendCommand(String command) throws RemoteException {
System.out.println("remote control asked for " + command);
}
}
The implementation of the common interface must extend java.rmi.server.UnicastRemoteObject
.
Create the actual server application which publishes an instance of the implementation of RemoteControlInterface
as remoteControl
as a server that is listening on port 1234
.
package com.example.remote.server;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Server {
public static void main(String[] args) throws MalformedURLException, RemoteException, AlreadyBoundException {
Registry registry = LocateRegistry.createRegistry(1234);
registry.bind("remoteControl", new RemoteControl());
}
}
Step 3: Create the client application
Create the actual client application which connects to a server on port 1234
and retrieves a published instance of RemoteControlInterface
using the name remoteControl
.
package com.example.remote.client;
import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import com.example.remote.RemoteControlInterface;
public class Client {
public static void main(String[] args) throws AccessException, RemoteException, NotBoundException {
Registry registry = LocateRegistry.getRegistry(1234);
RemoteControlInterface greetingService = (RemoteControlInterface) registry.lookup("remoteControl");
greetingService.sendCommand("helloWorld");
}
}
This will cause the server application to print remote control asked for helloWorld
on its console.
The parameters and the return value of all methods in the common interface may be:
- Any primitive Java type (boolean, int, ...)
- Any class the both applications share (String, Date, ...) that implements
java.io.Serializable
as long as both applications have the same version of the corresponding class file. The letter is true for all classes that are provided by the JRE and all classes placed in the common library.
While RMI can do much more, this should be sufficient to implement a simple remote control.