# Mehrere Clients über Java-Sockets



## d3rbastl3r (17. Okt 2011)

Hallo,

in meinem letzten Thread habe ich überlegt wie ich die Verbindung am besten managen soll (Socket oder RMI).
Nun habe ich mich für Java-Socket entschieden.

Jetzt stellt sich mir die Frage, wie ich am besten die Verbindungen mit mehreren Clients managen soll.

 Ich gehe über einen einzelnen Port, egal ob LogIn, CreateAccount oder sonstiger Informationsaustausch. Was der Benutzer gerade machen möchte entscheide ich anhand des Objektes welchen ich über ObjectInputStream bekomme.

 Ich trenne LogIn, CreateAccount und sonstigen Informationsaustausch auf mehrere Ports auf. (1234 = LogIn, 1235 = CreateAccount, 1236 = Sonstiges)
Hier stellt sich mir nun die Frage ob ich nach dem LogIn den Port des Clients von 1234 auf 1236 ändern kann, ohne die Verbindung trennen zu müssen.

 Jeder Client kriegt einen Eigenen Port ...

Wie gehe ich da am sinnvollsten vor ??


----------



## TheRealSpikee (18. Okt 2011)

1.) Das wohl einfachste und am häufigsten verwendete System ... ist zu empfehlen ...

2.) Es gibt Systeme welche mit mehreren "Server-"diensten arbeiten ... aber als Trennung für einzelne Befehle ist das OverKill. Sowas wird nur verwendet wenn du mehrere Server-Dienst simultan brauchst und jeder Dienst sich auf eine Aufgabe spezialisiert hat *z.B. AccountManagemet , inGame-World , etc* ... also wirklich große Dinge ... und nicht einfaches spiltten von Befehlen ...
Außerdem ist es NICHT möglich den Port "zu wechseln" ohne die aktuelle Verbindung zu trennen. TCP-Verbindungen sind immer END-TO-END ... also von einem Port des Quell-Rechners zu einem Port des Ziel-Rechners ... während diese Verbindung besteht kannst du da nichts dran ändern.

3.) extrem schlechte und so gut wie nicht umsetzbare Idee ... keinen weiteren Kommentar ... vergiss diese Möglichkeit ganz einfach ...


----------



## r.w. (18. Okt 2011)

Ich denke Writing the Server Side of a Socket (The Java™ Tutorials > Custom Networking > All About Sockets) sollte Dir weiterhelfen. 
Dort speziell der letzte Abschnitt "Supporting Multiple Clients".

VG ROlf


----------



## d3rbastl3r (19. Okt 2011)

Vielen dank Erstmal  



TheRealSpikee hat gesagt.:


> 1.) Das wohl einfachste und am häufigsten verwendete System ... ist zu empfehlen ...



Ja, so kannte ich das auch ...



TheRealSpikee hat gesagt.:


> 2.) Es gibt Systeme welche mit mehreren "Server-"diensten arbeiten ... aber als Trennung für einzelne Befehle ist das OverKill. Sowas wird nur verwendet wenn du mehrere Server-Dienst simultan brauchst und jeder Dienst sich auf eine Aufgabe spezialisiert hat *z.B. AccountManagemet , inGame-World , etc* ... also wirklich große Dinge ... und nicht einfaches spiltten von Befehlen ...
> Außerdem ist es NICHT möglich den Port "zu wechseln" ohne die aktuelle Verbindung zu trennen. TCP-Verbindungen sind immer END-TO-END ... also von einem Port des Quell-Rechners zu einem Port des Ziel-Rechners ... während diese Verbindung besteht kannst du da nichts dran ändern.



Gilt das auch für 2 Parallel laufende Systeme die unabhängig von einander funktionieren sollten ?
z.B.: Ein Chat in einem bestimmten Programm ... (stürtzt der Server des Programms ab so kann der Chat weiter funktionieren da dieser über einen anderen Server und Port läuft ??)



TheRealSpikee hat gesagt.:


> 3.) extrem schlechte und so gut wie nicht umsetzbare Idee ... keinen weiteren Kommentar ... vergiss diese Möglichkeit ganz einfach ...



Nach dem ich einen Server/Client Prototypen geschrieben habe ist mir auch aufgefallen dass diese Vorgehensweise einfach nur schwachsinnig ist, jedoch wäre das für mich (auf den ersten Blick) generell umsetzbar.

Hmm ... wieso ist das nicht umsetzbar ???
Welche Probleme ergeben sich bei so einer Vorgehensweise ?
Anfangs war ja meine Idee dass der Client über den UDP-Port den TCP-Port bekommt und sich dann über diesen zu dem Server verbinden kann.


----------



## d3rbastl3r (19. Okt 2011)

r.w. hat gesagt.:


> Ich denke Writing the Server Side of a Socket (The Java™ Tutorials > Custom Networking > All About Sockets) sollte Dir weiterhelfen.
> Dort speziell der letzte Abschnitt "Supporting Multiple Clients".
> 
> VG ROlf



Ja, so habe ich meinen Prototypen dann auch umgesetzt. (ClientAccessManager nimmt eingehende verbindungen der Clients entgegen und ClientManager wird dann für jeden verbundenen Client in einem eigenen Thread gestartet und kümmert sich erstmals um alle weiteren Anfragen des Clients)


----------



## Xeonkryptos (19. Okt 2011)

d3rbastl3r hat gesagt.:


> Hmm ... wieso ist das nicht umsetzbar ???
> Welche Probleme ergeben sich bei so einer Vorgehensweise ?.



Es gibt dann ggf. Probleme mit der Firewall: Lässt auch nicht alles zu. Weiterhin musst du bedenken, es gibt meines Wissens nach nicht unendliche Ports und irgendwann hast du das Maximum erreicht! Und wohl das größte Problem, welches mir in den Sinn kommt, es laufen auch andere Programme neben deinem und wollen auch im Internet kommunizieren und blockieren automatisch diesen Port, dann will dein Programm darüber kommunizieren und du kannst durch die Blockade keine Verbindung aufbauen.
Du musst bedenken, dass du bei Verbindungen im Internet immer einen Port wählen musst, der von KEINEM(!) anderen Programm schon verwendet wird, weil wenn dies der Fall ist, ist der Port gesperrt, macht auch Sinn. 

Es ist halt eine schlechte Lösung. Denke mal über diese Fragen nach: Für was brauchst du für jede neue Verbindung einen neuen Port?


----------



## d3rbastl3r (24. Okt 2011)

Xeonkryptos hat gesagt.:


> Es gibt dann ggf. Probleme mit der Firewall: Lässt auch nicht alles zu. Weiterhin musst du bedenken, es gibt meines Wissens nach nicht unendliche Ports und irgendwann hast du das Maximum erreicht!



ja, meines wissens nach gibt es 2^16 ports = 65.536 und wenn man sagen würde (ich beschrenke mich auf den bereich zwischen 10.000 und 20.000 hat man (denk ich mal) genug 



Xeonkryptos hat gesagt.:


> Und wohl das größte Problem, welches mir in den Sinn kommt, es laufen auch andere Programme neben deinem und wollen auch im Internet kommunizieren und blockieren automatisch diesen Port, dann will dein Programm darüber kommunizieren und du kannst durch die Blockade keine Verbindung aufbauen.



In meinen Augen ist das kein Problem. Wenn man den Server auf nem eigenem Server laufen lässt wo nicht so viele programme installiert sind ...



Xeonkryptos hat gesagt.:


> Du musst bedenken, dass du bei Verbindungen im Internet immer einen Port wählen musst, der von KEINEM(!) anderen Programm schon verwendet wird, weil wenn dies der Fall ist, ist der Port gesperrt, macht auch Sinn.



Naja, man kann auch vorher überprüfen ob ein gewisser port besetzt ist, wenn das der Fall sein sollte, könnte man diesen wechseln.



Xeonkryptos hat gesagt.:


> Es ist halt eine schlechte Lösung. Denke mal über diese Fragen nach: Für was brauchst du für jede neue Verbindung einen neuen Port?



Und natürlich hast du Recht, das ergibt keinen sinn


----------



## Xeonkryptos (24. Okt 2011)

d3rbastl3r hat gesagt.:


> In meinen Augen ist das kein Problem. Wenn man den Server auf nem eigenem Server laufen lässt wo nicht so viele programme installiert sind ...



Und was ist dann mit dem Client? Den sollen bestimmt mehr als nur du bekommen, vor allem, wenn du planst, dass mehrere Verbindungen aufgebaut werden sollen. Der User hat halt auch andere Programme laufen, die du mit einschließen musst. Du darfst nicht immer nur vom Server aus denken, sondern auch, dass der User den selben Port für seinen Client benötigt.


----------



## d3rbastl3r (28. Okt 2011)

Xeonkryptos hat gesagt.:


> Und was ist dann mit dem Client? Den sollen bestimmt mehr als nur du bekommen, vor allem, wenn du planst, dass mehrere Verbindungen aufgebaut werden sollen. Der User hat halt auch andere Programme laufen, die du mit einschließen musst. Du darfst nicht immer nur vom Server aus denken, sondern auch, dass der User den selben Port für seinen Client benötigt.



Meines wissens nach wird bei dem Client kein fixer port benutzt. Wenn ich dem Client sage "verbinde dich mit dem Server über den Port 6000" dann gilt dieser Port nur auf der Serverseite, auf der Clientseite läuft die verbindung über einen anderen Port.

Ach ja, vielleicht noch ne Frage zu ObjectInputStream und ObjectOutputStream.
Bei dem Datenaustausch, schließe ich da immer den OIS und OOS oder lasse ich diese so lange bestehen bis auch die verbindung zum client getrennt werden soll.

z.B.:

```
Object obj;

ServerSocket serverSocket;
Socket client;
ObjectInputStream ois;
ObjectOutputStream oos;

client = serverSocket.accept();
ois = new ObjectInputStream(client.getInputStream());
oos = new ObjectOutputStream(client.getOutputStream());

obj = ois.readObject();
// Schließe ich an dieser Stelle mein ois ???

oos.writeObject(new Object());
// Schließe ich an dieser Stelle mein oos ???

// Wenn ich ois und oos vorhin geschlossen habe müsste ich diese an dieser stelle wieder neu initialisieren
obj = ois.readObject();
oos.writeObject(new Object());
```


----------



## SlaterB (28. Okt 2011)

einmal geschlossen wäre der Socket in die jeweilige Richtung tot, also wohl offen lassen


----------



## d3rbastl3r (28. Okt 2011)

SlaterB hat gesagt.:


> einmal geschlossen wäre der Socket in die jeweilige Richtung tot, also wohl offen lassen



Ok, das habe ich auch erst gedacht, deshalb habe ich ObjectOutputStream und ObjectInputStream als membervariablen angelegt und schon im Konstruktor initialisiert.

doch schon bei der initialisierung von ObjectInputStream blokiert das programm (ich hätte vermutet dass dieses erst bei "ois.readObject();" blokiert)

Im bezug auf meinen, oben angegebenen code würde eine System.out-Ausgabe niemals zustande kommen wenn ich diese zwischen zeile 9 und 10 setzen würde.

Was könnte der fehler sein ??


----------



## SlaterB (28. Okt 2011)

ObjectInputStream will gleicht was lesen, was ein geöffneter ObjectOutputStream schon schreibt, Beginn-Token vor den ersten Objekt,
wenn beide erst ObjectInputStream öffnen warten beide Seiten ewig,
öffnet mindestens eine Seite erst den ObjectOutputStream, dann klappt es folgerichtig,
zur Sicherheit auf beiden Seiten immer erst Out, dann In

--------

eine nicht ganz zu vernachlässigende Variante zum vorherigen Theme, zum offen halten:
über den Socket-Stream nur normale Bytes versenden,

ObjectStreams in separaten Stream in ein byte[] schreiben, dann auch close() möglich, 
es kommt ein byte[] raus, dieses versenden über den offengehaltenen Socket-Stream


----------



## d3rbastl3r (28. Okt 2011)

SlaterB hat gesagt.:


> eine nicht ganz zu vernachlässigende Variante zum vorherigen Theme, zum offen halten:
> über den Socket-Stream nur normale Bytes versenden,
> 
> ObjectStreams in separaten Stream in ein byte[] schreiben, dann auch close() möglich,
> es kommt ein byte[] raus, dieses versenden über den offengehaltenen Socket-Stream



Verstehe nicht ganz worauf du hinaus willst 
Soll man mit ObjecStream keine Objekte-Streamen sondern besser mit SocketStream ??


----------



## SlaterB (28. Okt 2011)

es wäre über eine Variante über Sockets keine ObjectStreams zu eröffnen (die komplizierte bytes verschicken) sondern einfach nur bytes,

welche bytes, das ist dann eine separate Frage, können auf beliebige Weise gewonnen werden, z.B. durch separate ObjectStreams woanders im Programm, welche du dann gleich schließen könntest, da sie dort (=woanders) den Socket nicht interessieren

vergleichbar mit Swing auf einem BufferedImage malen und in paintComponent nur das Image darstellen,
falls dir das bekannt ist


----------

