# RMI-Funktion wird lokal ausgeführt



## LeRoi (9. Dez 2007)

Hallo miteinander,

ich hab folgendes Problem mit RMI.
Ich schreibe ein kleines Programm bei welchem ein Client einen String an einen Server sendet
und dieser den String unbehandelt wieder zurück sendet (quasi nen echo). Der Client misst dabei
die benötigte Zeit. Das ganze wird mit verschiedenen Größen gemacht um eine Aussage über
Übertragungsrate etc. machen zu können. Nun hab ich folgendes Problem, ich habe 2 PC's
auf den einmal der Server auf den anderen der Client läuft. Nach der Zeitmessung brauchten selbst
grössere Daten (64MB) nur ein paar hundert Millisekunden für den Weg was mich stutzig machte. Ein println()
auf Serverseite ergab eine Ausgabe der Strings in der Console des Clients und nicht auf der Console des Servers.
Quasi wurde die Funktion lokal behandelt und nicht auf dem entfernten Rechner. Meine Frage ist: Wieso?? Müsste der 
Stub das nicht an die Serinstanz auf den entfernten rechner weiterleiten??

Hier mal Auszüge aus dem Programm, ich find irgendwie nichts komisches dabei:

Server:


```
LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
System.setSecurityManager(new RMISecurityManager());
Naming.rebind("RTTServer", im);
System.out.println("Server ready");
```
Echo-Funktion auf dem Server:

```
public String echo(String s) throws RemoteException {
	
    	return s;
	}
```

Client:


```
IServer server = (IServer) Naming.lookup("rmi://" + host
					+ "/RTTServer");
			server.echo("Test");
```

Ich hoffe jemand weiß ne Lösung, wäre dafür sehr dankbar.

MfG LeRoi


----------



## Guest (9. Dez 2007)

Wie sieht die IServer Implementierung aus?


----------



## LeRoi (10. Dez 2007)

Die Implementierung sieht folgendermaßen aus:

```
public class ServerImpl extends UnicastRemoteObject implements IServer, Serializable{

	public ServerImpl() throws RemoteException {
		super();
	}
	
	

	private static final long serialVersionUID = 312248762588433799L;

       qOverride
	public String echo(String s) throws RemoteException {
		
    	return s;
	}

}
```

Es funktioniert jetzt tatsächlich, aber erst seitdem ich von UnicastRemoteObject erbe. Eigentlich
implementiert das ganze ja auch nur REmote und Serializable. Was ich ja vorher mit IServer und Ser.
auch schon hatte. Kann einer sagen wo da der Unterschied ist? Also wieso man UnicastRemoteObject 
verwenden muss??

mfg LeRoi


----------



## tuxedo (10. Dez 2007)

Ist RMI nicht ein wenig "overkill" für eine Laufzeitmessung? Zumal ja RMI nicht gerade Firewall/Router freundlich istund unter umständen mehr als nur eine Socketverbindung benutzt ...

Oder war das nur zum testen der RMI-Geschwindigkeit gedacht? Was hast du denn für Messergebnisse erhalten?

- Alex


----------



## LeRoi (10. Dez 2007)

Das mit dem "overkill" stimmt. Das Programm soll aber auch genau das feststellen, also wie groß der Overhead
zwischen "nativen" Sockets und RMI ist. Und ob man es glaubt oder nicht im loaklen Netze gibts es nicht so
wahnsinnige Unterschiede im Transfervolumen (+10%). Jedenfalls nicht nach meinen Berechnunegn. Aber 
ich bin auch noch am testen.

mfg LeRoi


----------



## tuxedo (10. Dez 2007)

Bin so nebenher dabei ein "besseres" RMI zu schreiben. Eins das nur eine Socketverbindung nutzt statt mehrere (im Fall der Callback-Benutzung). 

So von der Technik her würd ich sagen dass da nicht allzuviel Traffic erzeugt wird. Die einzelnen Methodenaufrufe erzeugen recht wenig overhead. Bei mir wird hier nur der Name des Objekts, sowie der Name der aufzurufenden Methode, als auch die Parameter serialisiert. Klar. Je komplexer die Parameter sind, desto größer der Overhead (bedingt durch den Objekt-Overhead). 

Wenn du genaueres gemessen hast lass es uns wissen. 

- Alex


----------



## Gast (14. Dez 2007)

Hallo,



> ... Also wieso man UnicastRemoteObject
> verwenden muss?



Weiss darauf jemand zufällig eine Antowrt?

Grüße,
Christian


----------



## HoaX (14. Dez 2007)

LeRoi hat gesagt.:
			
		

> Es funktioniert jetzt tatsächlich, aber erst seitdem ich von UnicastRemoteObject erbe. Eigentlich
> implementiert das ganze ja auch nur REmote und Serializable. Was ich ja vorher mit IServer und Ser.
> auch schon hatte. Kann einer sagen wo da der Unterschied ist? Also wieso man UnicastRemoteObject
> verwenden muss??



a) weil es so ist 
b) wenn du in die apidoc schaust sieht du, dass UnicastRemoteObject mehr bietet als die 2 Interfaces zu implementieren


----------



## Gast (17. Dez 2007)

Aber wie bekomme ich dann (sauber!) die folgende Klasse dazu, von UnicastRemoteObject zu erben?



```
public class NetworkAcceptor extends Acceptor implements Serializable, NetworkAcceptorInterface {
...
}
```

Die Basisklasse hat absolut nichts mit Netzwerken zu tun - und sollte insofern auch nicht von UnicastRemoteObject erben...

*sic*.


----------



## tuxedo (17. Dez 2007)

Also ich kenn keinen anderen Weg außer von UnicastRemoteObject zu erben... Von daher wirst du dein Design anpassen müssen.

Außer es ist hier jemand schlaucher und kennt eine andere Lösung ..

- Alex


----------



## Gast (17. Dez 2007)

Also irgendwie komme ich nicht weiter, obwohl ich hier und auch anderen Stellen durch das Netz stöber... Anfänglich hatte ich auch das Problem, daß meine Methoden lokal aufgerufen werden. Daher jetzt der manuelle Export über das UnicastRemoteObject.

Bei meinem Code:


```
...
    /**
     * Die NetworkAcceptoren im Netzwerk publizieren.
     * 
     * @param discoveryManager Der DiscoveryManager.
     */
    public void publishNetworkAcceptors(DiscoveryManager discoveryManager) {
        for (int i = 0; i < networkAcceptors.size(); i++) {
            NetworkAcceptor acceptor = networkAcceptors.get(i);
            try {
                logger.debug("RMI: Registriere '" + acceptor.getName() + "'");
                acceptor = (NetworkAcceptor) whatIsIt(UnicastRemoteObject.exportObject(acceptor, 0));
                LocateRegistry.getRegistry(Registry.REGISTRY_PORT).bind(acceptor.getName(), acceptor);

                logger.debug("Bonjour: Populiere " + acceptor.getName() + " in Bonjour.");
                discoveryManager.addNetworkAcceptor(acceptor);
            } catch (Exception ex) {
                logger.fatal("FATAL", ex);
            }
        }
    }

    private Object whatIsIt(Object o) {
        logger.debug("Object is "+o);
        return o;
    }
    ...
```

bekomme ich die Meldung (Fehler bezieht sich auf die Zeile 13 mit dem UnicastRemoteObject):


```
2007-12-17 15:22:12,126 DEBUG [main] (Element.java:138) - RMI: Registriere '[IP|1744155] Eingang'
2007-12-17 15:22:12,343 DEBUG [main] (Element.java:151) - Object is Proxy[NetworkAcceptorInterface,RemoteObjectInvocationHandler[UnicastRef [liveRef: [endpoint:[134.60.236.229:52517](local),objID:[0]]]]]
2007-12-17 15:22:12,352 FATAL [main] (Element.java:145) - FATAL
java.lang.ClassCastException: $Proxy0
        at de.logistik.simulation.Element.publishNetworkAcceptors(Element.java:139)
        at de.logistik.simulation.ElementListe.publishNetworkAcceptors(ElementListe.java:109)
        at de.logistik.Simulation.publishNetworkAcceptors(Simulation.java:232)
        at de.logistik.Simulation.main(Simulation.java:221)
```

Was ja eigentlich bedeutet, ich erbe nicht von Remote in meinem Interface. Aber das sieht so aus:


```
/*
 * NetworkAcceptorInterface.java
 *
 * Created on 24. März 2007, 14:20
 */
package de.logistik.network.rmi;

import de.logistik.exceptions.UnknownColorException;
import de.logistik.exceptions.UnknownParameterException;
import de.logistik.exceptions.WrongCubeException;
import de.logistik.simulation.Cube;
import de.logistik.simulation.Element;
import java.rmi.Remote;
import java.rmi.RemoteException;

/**
 * Das Interface für RMI.
 * 
 * @author caschoff
 * @version 1.0
 */
public interface NetworkAcceptorInterface extends Remote {

    public boolean accept(Cube wuerfel)
            throws WrongCubeException, UnknownColorException, UnknownParameterException, RemoteException;

    public int getFilterColor()
            throws RemoteException;

    public Element getElement()
            throws RemoteException;
    
    public String getName()
            throws RemoteException;
}
```

... und die Implementierung so:


```
/*
 * NetworkAcceptorInterface.java
 *
 * Created on 24. März 2007, 14:20
 */
package de.logistik.network.rmi;

import de.logistik.simulation.Acceptor;
import java.io.Serializable;
import org.apache.log4j.Logger;

/**
 * Der NetzwerkAcceptor braucht einen eindeutigen Namen!
 * 
 * @author caschoff
 * @version 1.0
 */
public class NetworkAcceptor extends Acceptor implements Serializable, NetworkAcceptorInterface {

    /** Der Logger. Siehe log4j.properties. */
    private static final Logger logger = Logger.getLogger(NetworkAcceptor.class);
    /** Ein Prefix für den Namen, damit er eindeutig wird. */
    private String prefix;

    public NetworkAcceptor(String name, int filterColor) {
        super(name, filterColor);

        prefix = "[IP|" + hashCode() + "] ";
    }

    @Override
    public String getName() {
        return prefix + super.getName();
    }

    @Override
    public String toString() {
        return "NetworkAcceptor [name = " + getName() + ", colorFilter = " + getFilterColor() + ", element = " + getElement() + "]";
    }
}
```

Irgendein Tipp?

Grüße,
Christian


----------



## Niki (17. Dez 2007)

Nur am Rande, man muss nicht von UnicastRemoteObject ableiten. Du kannst das Objekt auch einfach exportieren. Dann kann es von jeder x-beliebigen Klasse ableiten:
exportObject


----------



## Guest (17. Dez 2007)

> Nur am Rande, man muss nicht von UnicastRemoteObject ableiten. Du kannst das Objekt auch einfach exportieren. Dann kann es von jeder x-beliebigen Klasse ableiten



Ja, das mache ich ja in Zeile 13 des ersten Quellcodes...


----------

