Vorwort
Wer Client-Server Anwendungen mit RMI geschrieben hat, und diese versucht hat über’s Internet zu benutzen kennt vermutlich das Phänomen: Nix geht mehr. Ob der Server dabei hinter einem DSL-Router hängt und mittels Portforwarding betrieben wird oder nicht scheint dabei keine Rolle zu spielen.
Warum ist RMI etwas ungeschickt bei der Kommunikation im Internet?
Warum? Vermutlich benutzt du eine Callback-Strategie die es dem Server erlaubt, selbstständig Methoden am Client aufzurufen. RMI benutzt hierfür nicht wie erwartet die Verbindung, die der Client zum Server aufgebaut hat, sondern baut von sich aus eine neue Verbindung auf. Da in Europa (und vermutlich der Rest der Welt) zu einem Großteil hinter einem Router sitzt, der für einen den Verbindungsaufbau zum Internet erledigt, bleibt der Verbindungsaufbau vom Server zum Client an diesem Router hängen.
Die Lösung
Nun, SIMON ist hierfür die Lösung. SIMON nutzt nur eine einzige Netzwerkverbindung für die bi-direktionale Kommunikation. Nämlich die, die der Client zum Server hin aufbaut. Damit muss maximal für den Server ein Portforwarding konfiguriert werden. Mehr nicht.
Doch das ist noch nicht das Ende vom Lied:
RMI nutzt das normale Java IO. Das hat zum Nachteil, dass ein Server, der mehrere Clients bedienen soll, für jeden Client einen Thread starten muss. Das mag für eine Hand voll User noch gut gehen. Aber stell dir einen Server mit über 1000 Clients vor? Der Server wäre mit 1000 Threads nur für die Clients schon recht stark belastet. MIt steigender Client-Zahl nimmt die Zeit, die er für’s Dispatchen der vielen Threads braucht stetig zu und irgendwann kann er gar keinen Client mehr bedienen weil ihm die Ressourcen ausgehen.
SIMON verwendet hier nicht das alte IO, sondern das neue NIO (okay, das ist auch schon älter, aber bedeutend skalierbarer). SIMON kann so konfiguriert werden, dass eine beliebige Anzahl Clients mit einer begrenzten Anzahl an Threads bedient werden. Damit werden die Ressourcen geschont, der Server ist noch ansprechbar und das System lebt weiter.
Performance
In Tests konnte SIMON bis jetzt 3000 Clients mit rund 50 Threads bedienen. Geschwindigkeitsprobleme mit so wenig Threads? Nein. Im Gegenteil. Im Tests konnte der Server noch 10.000 (in Worten: Zehntausend!) Methodenaufrufe pro Sekunde bewältigen. Das ist doch schon eine ganze Menge (Testumgebung: Intel Core2 Quad 6600 mit 4x2,4Ghz, 4GB RAM, OS: openSUSE Linux, Verbindung zwischen Clients und Server via localhost).
Dazu kommt noch, dass SIMON etwas einfacher zu handhaben ist als RMI. Es gibt weniger Dinge die man beachten muss. Und da SIMON noch entwickelt wird, fließen die Anregungen und Wünsche der Anwender direkt in die Entwicklung mit ein.
Ein Codebeispiel
Damit du einen Überblick bekommst wie SIMON funktionier, hier ein Codesample:
ServerInterface.java:
import de.root1.simon.SimonRemote;
import de.root1.simon.SimonRemoteException;
public interface ServerInterface extends SimonRemote {
public void login(ClientCallbackInterface clientCallback) throws SimonRemoteException;
}```
ClientCallbackInterface.java
```package de.root1.simon.codesample.common;
import de.root1.simon.SimonRemote;
import de.root1.simon.SimonRemoteException;
public interface ClientCallbackInterface extends SimonRemote {
public void callback(String text) throws SimonRemoteException;
}```
ServerInterfaceImpl.java
```package de.root1.simon.codesample.server;
import de.root1.simon.SimonRemoteException;
import de.root1.simon.codesample.common.ClientCallbackInterface;
import de.root1.simon.codesample.common.ServerInterface;
public class ServerInterfaceImpl implements ServerInterface {
private static final long serialVersionUID = 1L;
public void login(ClientCallbackInterface clientCallback) throws SimonRemoteException {
clientCallback.callback("This is the callback. " +
"Your address is "+Simon.getRemoteInetAddress(clientCallback)+" "+
"and your are connected from port "+Simon.getRemotePort(clientCallback));
}
}```
ClientCallbackImpl.java
```package de.root1.simon.codesample.client;
import de.root1.simon.SimonRemoteException;
import de.root1.simon.codesample.common.ClientCallbackInterface;
public class ClientCallbackImpl implements ClientCallbackInterface {
private static final long serialVersionUID = 1L;
public void callback(String text) throws SimonRemoteException {
System.out.println("This message was received from the server: "+text);
}
} ```
Server.java
```package de.root1.simon.codesample.server;
import de.root1.simon.Simon;
public class Server {
public static void main(String[] args) {
// create the serverobject
ServerInterfaceImpl serverImpl = new ServerInterfaceImpl();
// create the server's registry ...
Simon.createRegistry(2000);
// ... where we can bind the serverobject to
Simon.bind("server", serverImpl);
System.out.println("Server up and running!");
}
} ```
Client.java
```package de.root1.simon.codesample.client;
import de.root1.simon.Simon;
import de.root1.simon.SimonRemoteException;
import de.root1.simon.codesample.common.ServerInterface;
public class Client {
public static void main(String[] args) throws SimonRemoteException, ConnectException {
// create a callback object
ClientCallbackImpl clientCallbackImpl = new ClientCallbackImpl();
// 'lookup' the server object
ServerInterface server = (ServerInterface) Simon.lookup("127.0.0.1", 2000, "server");
// use the serverobject as it would exist on your local machine
server.login(clientCallbackImpl);
// do some more stuff
// and finally 'release' the serverobject to release the connection
Simon.release(server);
}
}```
So, mehr ist es im Prinzip nicht. Wer RMI kennt, findet sich hier schnell zurecht. Und wer RMI nicht kennt, und mit Interfaces umgehen kann, der findet sich ebenfalls recht schnell zurecht.
**Weitere Infos, Download, etc.**
Bei Fragen, Anregungen, Ideen und dergleichen, bitte besucht die Projektseite unter
http://www.root1.de
Dort gibts nightly builds, Codesamples, Doku, ein Support-Forum und einen Bugtracker wo ihr Fehler berichten könnt und immer auf dem laufenden bleibt.
Kleiner Hinweis: Die Seite ist zwar auf englisch, aber das Support-Forum ist zweisprachig. In der Regel bekommt ihr binnen 24h auch eine brauchbare Antwort von mir.
Gruß,
Alex