# Grundlegende Fragen zu einem Verbindungsaufbau in einem LAN



## Braain (13. Jun 2012)

Guten Tag,

ich habe ein paar Fragen zum Thema Netzwerkprogrammierung.

Mein Ziel bzw. meine Aufgabe ist folgendes:
Ich habe das Spiel Schiffeversenken programmiert und möchte es nun netzwerkfähig machen. Es soll 
aber nur ganz einfach ausfallen. Es gibt nur 2 Spieler, die sich im selben Netzwerk befinden. D.h.
vereinfacht gesagt, dass beide Spieler das Spiel starten, es wird eine Verbindung aufgebaut und sie
können gegeneinander spielen.

Ich hab jetzt angefangen mich ein bisschen einzulesen und bin dann relativ schnell auf RMI gestoßen.
Doch wenn ich das richtig verstanden hab, dann benötige ich dort immer eine feste IP bei der ich
mich "anmelden" kann. Aber die IP ist ja jedes Mal eine Andere.

Mein Gedankengang ist nun folgender. Da ich nur in einem Lan bin und somit eine begrenzte Anzahl an
IP-Adressen habe, müsste es doch möglich sein, dass ich überall einen bestimmten Port abfrage und
auf eine Antwort warte. Soll konkret heißen, dass Spieler 1 alle IP-Adressen abfrägt. Natürlich
bekommt er keine Antwort. Als nächstes wird er dann zum "Server" und wartet auf eine Anfrage. Wenn 
Spieler 2 nun alle abfrägt, müsste er eine Antwort bekommen.

Meine Frage ist nun, ob das möglich ist und wie aufwendig das ist oder ob es bessere Wege gibt das Problem zu lösen?

ich bedank mich schonmal im voraus 

mfg


----------



## Multicast (13. Jun 2012)

IP-Range-Scan ist sicherlich die wohl schlechtest Variante. Auch müsstest du dabei erstmal die IP und SubNetMask des Systems auslesen.
Das wohl Einfachste wäre einfach ein JTextField zu machen in dem man dann die Ziel-IP eingeben kann.
Vorteil : wäre dann (wenn beim Ziel-Host Port-Weiterleitung im NAT-Router aktiv ist) sogar übers Netz spielbar.
Nachteil : viele User wissen nicht wie sie an ihre LAN-IP kommen.
Eine andere und weit verbreitete Möglichkeit wäre Multicast. Dabei sendet der Client z.B. einen Multicast ins LAN und wartet auf Antworten von laufenden Servern. Diese kann man dann in einer Liste darstelle und eine Möglichkeit zum "direct-connect" z.B. einen Button geben. Der Verbindungs-Aufbau läuft dann intern aus den von der Antwort erhaltenen Daten ab.
Vorteil : weit verbreitet und etablierte Technik für "LAN"
Nachteil : funktioniert nur in relativ kleinen und einfachen LANs , übers WAN garnicht (da Multicast nicht geroutet wird) und die Chance das sich das Multicast-Paket in großen komplexen LANs mit mehreren SubNets verliert ist relativ hoch.

Das wäre jetzt die Erklärung wie man einen anderen Host in einem LAN "finden" kann falls man seine IP nicht genau kennt.

Oder wolltest du noch zusätzlich Infos wie du dann den konkreten Verbindungs-Aufbau durchführst und wie du die Daten austauschst ?


----------



## c_sidi90 (14. Jun 2012)

Wieso implementierst du nicht bei jedem Client eine Methode welche die IP-Adresse automatisch ermittelt und in ein Textfeld oder Label anzeigt? Das geht doch super easy über die InetAddress Klasse.


----------



## Braain (14. Jun 2012)

Danke für die Antworten.

Ich werd mir das mit dem Multicast auf jeden Fall mal anschauen. Und als Plan B kann ich ja immer noch den 
manuellen Weg verwenden.


----------



## tuxedo (14. Jun 2012)

Oder du benutzt SIMON (siehe Signatur). 

Damit erschlägst du 2 Fliegen mit einer Klappe:

1. Mit SIMON hat du den RMI-Komfort (und sogar noch ein wenig mehr)
2. SIMON beherrscht von Haus aus das Auffinden von Servern im lokalen Netzwerk: Ein Spieler macht den Server, der andere lässt ihn suchen und finden, und verbindet sich zu ihm. Das "Auffindbarmachen" des Servers ist eine Code-Zeile mehr (als ohne), das Finden sind nur eine Handvoll Zeilen (inklusive Progress-Listner).

- Alex


----------



## Multicast (14. Jun 2012)

tuxedo hat gesagt.:


> Oder du benutzt SIMON (siehe Signatur).
> 
> Damit erschlägst du 2 Fliegen mit einer Klappe:
> 
> ...



Würde wetten das SIMON das auch nur über Multicast oder andere UDP-Spielereien macht.
Und ob man nun ein solches Framework nimmt und sich mit RPC (RMI ist nur eine Java-spezifische Impl) auseinander setzt nur weil man dessen Möglichkeit nutzen will im LAN etwas zu finden oder das selbst mit Multicast / UDP implementiert ist eigentlich egal. Man braucht für beides das Hintergrundwissen und die Erfahrung/Übung.


----------



## tuxedo (14. Jun 2012)

Na klar benutzt SIMON da keine "Wundervolle Magie". SIMON ist auch nur mit Wasser (bzw. Java) gekocht. 

Der TS hätte ja RMI schon benutzt, aber er hat das Problem mit dem auffinden des Servers. Von daher bietet sich SIMON an, da SIMON hier die Komplexität der "Auffindvorgangs" kapselt und eine wirklich einfache Schnittstelle hierfür bietet. 

Ob man "das was dahinter abläuft" unbedingt verstehen muss, darüber kann man streiten. Allgemein gesagt: Ich stimm dir zu. Besser ist es wenn man weiß was dahinter passiert. Aber notwendig ist das nicht immer. Siehe JBoss und Konsorten. Die meisten haben keine Ahnung von den vielen Proxy-Schichten der EE-Container und dem Classloader-Aufwand, sowie der ByteCode Manipulation der dahinter steckt. Und dennoch wird's groß und breit eingesetzt...Solange alles funktioniert wie gewünscht hat man folgendes damit erreicht: Geringe Lernkurve (geringer als wenn man TCP und Multicast-Kommnuniation oder das ganze Proxy/Classloader/ByteCode Manipulationsgeraffel verstehen müsste) und schneller ein fertiges Produkt. Wenns Probleme gibt kann man dann immernoch nachschlagen wie das alles funktoniert.


----------



## Braain (15. Jun 2012)

In dem Fall ist es mir wichtig alles zu verstehen, da ich das Programm für mein mündliches Abitur benötige 

Aber der Grund warum ich nochmal schreibe, ist, weil ich noch einmal eure Hilfe benötige. Diesmal bei RMI.  Damit komm ich noch überhaupt nicht klar.

Mein Problem:
Eine Methode wird aufgerufen. Diese ist dafür zuständig, dass der Server erstellt wird und Spieler 1, auf dessen PC sich der Server befindet, sich direkt verbindet. Aber egal wie ich es mache, ich bekomme immer eine "NotBoundException".


----------



## tuxedo (15. Jun 2012)

Tut mir leid. Meine Glaskugel ist gerade in der Werkstatt. Meine hellseherischen Fähigkeiten ohne Glaskugel sind leider immens schlecht.

Schon mal auf die Idee gekommen ein bisschen Code zu deinem Problem zu posten ???:L


----------



## Multicast (15. Jun 2012)

made my day =)

Ach ja, die gute alte Glaskugel ... immer wieder schöne Anspielung.

Nein im ernst : bei RPC kann ich dir leider nicht mehr weiter helfen (RMI ist nur die Java-spezifische implementierung des RPC-Pattern, genau wie SIMON auch nur eine andere Implementierung ist).

Wenn es wichtig ist das du verstehst was da abläuft müsstest du dich soweit mit SIMON beschäftigen das du genau weist wie das "Auffinden" genau implementiert wurde (wenn du es halt nicht selbst machen willst).

Ansonsten klingt "NotBoundException" für mich eher danach das auf einer der beiden Seiten irgendwas nicht "registriert" wurde oder Wrapper-Klassen fehlen. Versuch erstmal mit einem kleinen Beispiel überhaupt die Implementierung zum laufen zu bekommen und bau diese dann erst ins Spiel ein. Wenn du gleich in deinem Spiel "rumspielst" läufst du gefahr den gesamten NetCode zu zerstückeln das nachher garnichts mehr hinhaut.

Ist halt alles etwas komplizierter als bloß die paar Zeilen Verbindung und Calls, und ohne Framework ein ganz schöner Aufwand.


----------



## Braain (15. Jun 2012)

Tut mir leid. Ich hätte mich ein bisschen verständlicher ausdrücken müssen. Mein produzierter Code ist 
im Müll gelandet  Hatte gerade einen kleinen Durchhänger, weil ich schon den ganzen Tag nicht 
voran komme. Was ich eigentlich wollte, ist ein verständliches Tutorial oder sowas in der Art. Mit "Java 
ist auch eine Insel" komm ich nicht wirklich weiter. Außerdem hab ich so noch ein paar Fragen:

Muss ich den Server dann in einen eigenen Thread packen? Ist eigentlich das Einzige was Sinn macht.
Wenn ich dann alles in der Methode starte und der Server seperat läuft, kann der andere PC dann 
trotzdem die Registry finden?
Oder auch hier. Der Code des Clients aus "Java ist auch eine Insel"

```
public static void main( String[] args ) throws  RemoteException, NotBoundException
  {
    Registry registry = LocateRegistry.getRegistry();
    Adder adder = (Adder) registry.lookup( "Adder" );
    System.out.println( adder.add( 47, 11 ) );
  }
```
Ich komm da nicht ganz mit. Woher weiß der PC wo er die Registry nachschauen muss? Durch das viele lesen ist inzwischen nur noch komplette Verwirrung entstanden...

edit:

ich probiers ja im kleinen zum laufen zu bekommen. Das Problem ist nur das bei mir ein Client den 
Server start und sich dann damit verbinden soll. Und dazu hab ich bis jetzt noch nichts 
passendes im Netz gefunden.


----------



## Multicast (15. Jun 2012)

Du solltest auf jeden Fall den "Server"-Part in mindestens 2 eigenen a-synchronen Threads laufen lassen (einer der die Verbindung an sich annimmt und der andere der sich um den Daten-Austausch kümmert). Ansonsten würdest du die GUI stark belasten oder gar freezen.


----------



## tuxedo (15. Jun 2012)

RMI an sich muss man nicht in einen Thread packen. Das kapselt RMI alles für einen. Da aber ein Methodenaufruf über's Netzwerk durchaus etwas dauern kann, sollte der Aufrufer-Thread nicht der UI-Thread sein. 

Zum Thema "verstehen was abläuft weil ich's erklären können muss": Naja. Ob du da jetzt RMI oder SIMON nimmst: Völlig Jacke wie Hose. Beides ist RPC und benutzt Reflection sowie Proxies. Ich gehe sogar soweit und behaupte dass due am Ende SIMON besser erklären kannst als RMI. Grund: Wirkliche Details zu den RMi Internas (also das was über Wikipedia hinausgeht, denn das ist bei SIMON identisch) sind schlecht bis gar nicht dokumentiert. Außer im Source selbst. Und den liest man "nicht mal eben". Als ich SIMON entwickelt hab, hab ich mich hier und da durch den RMI Source "gekämpft". "Einfacher Code" ist anders ...

Hast du dir mal das SIMON-Hello-World angeschaut?

--> Sample helloworld110 - SIMON - root1.de - Software Engineering

Zur RMI Sache:

Denke du bist da auf dem Holzweg. Ein Clientseitiger Lookup sieht so aus:


```
MyService myService = (MyService) Naming.lookup("rmi://192.168.0.1:1099/MyService");
```

Gruß
Alex


----------



## Braain (15. Jun 2012)

Oh man...

Danke für die Antworten. Hab den Fehler gefunden. Jetzt funktioniert alles. Ich war einfach nur zu blöd 
für die Groß- und Kleinschreibung...


```
ServerSteuerung serverSteuerung = (ServerSteuerung) Naming.lookup("rmi://" + ip +"/Server");
```

Ich hab das Server ganz hinten klein geschrieben. Und auch vorher, als ich die Ip noch nicht mit drin
hatte, wäre es gegangen, da es ja ein lokaler Server ist. Naja ärgerlich, aber wieder was gelernt 

mfg


----------



## Kr0e (15. Jun 2012)

tuxedo hat gesagt.:


> RMI an sich muss man nicht in einen Thread packen. Das kapselt RMI alles für einen. Da aber ein Methodenaufruf über's Netzwerk durchaus etwas dauern kann, sollte der Aufrufer-Thread nicht der UI-Thread sein.




Asynchrones RMI ftw


----------



## Empire Phoenix (16. Jun 2012)

btw bau bitte trotzdem noch nen manuelles ip textfeld ein. 
Es gibt zuviele spiele wo die multicast implementierung einfach ab und zu rumbuggt (c&c zb.)
und es gibt netzwerkkonfigurationen die multicasts nicht durchlassen.


----------

