Hallo,
ich habe mich zuletzt recht intensiv mit java.net.* und der Server-Client-Entwicklung beschäftigt.
Als kleinen Test für mich selbst habe ich dann ein Client-Server-basiertes Chatprogramm für mehrere Clients für die Kommandozeile entwickelt, welches auch gut funktioniert hat, aber dennoch sehr simpel war.
Jetzt möchte ich das ganze verbessern, indem ich für den Server und den Client eine graphische Oberfläche entwickle und der User sich zudem mit einem Nickname und weiteren Daten anmelden kann usw.
Zu diesem Zweck möchte ich, dass der Client direkt nach dem verbinden über einen ObjectStream die von mir erstellte Klasse ClientInfo überträgt (werde ich jetzt hier nicht posten, enthält nur ein paar Attribute sowie getter und setter).
Nun bin ich mir nicht sicher, wie ich das realisieren soll; im Grunde wird jeder Client der sich verbindet in einem Thread gehandlet.
Derzeit habe ich folgende Klassen:
serverFrame = grafische Oberfläche, beinhaltet keinen relevanten Code
Server = extends Thread, läuft in Endlosschleife um eingehen Verbindungen anzunehmen.
ClientListener = extends Thread, für jede neue Verbindung (jeden neuen Socket) wird diese Klasse neu instanziert. Hier wird auf das eintreffen des ObjectStreams und dann im Anschluss auf eingehende Nachrichten gewartet.
Mein Problem: Wenn sich ein Client verbindet, aber kein ClientInfo im Anschluss sendet, läuft der Thread ewig weiter und wartet auf einen ObjectStream, ohne eine Möglichkeit diesen beenden zu können. Wie kann ich dieses Problem lösen?
Dieses Problem tritt z.B. auf, wenn ich versuche mit dem alten Kommandozeilenprogramm zu verbinden. Die Verbindung klappt, allerdings erhält der Server dann natürlich kein Object.
Hier der run-Methode der Server-Klasse:
Und hier die run-Methode der ClientListener-Klasse:
Dies wäre eigentlich meine Hauptfrage.
Ansonsten hätte ich noch zwei nebensächliche: Dieses Projekt ist bisher das größte, an dem ich bisher gearbeitet habe, und mir gefällt die Art meiner Programmierung nicht bzw. ich weiß nicht wie ich sie besser machen könnte.
Im Grunde ist ja alles von der serverFrame-Klasse abhängig. Dort werden die Vectoren für die Clients initialisiert und noch einige andere Variablen.
Diese muss ich natürlich weitergeben. Allein die Klasse mClients (ein Vector, der alle ClientInfos hält) wird vom ServerFrame an die Klasse Server weitergegeben, von da an die Klasse ClientListener usw. So kommt es dazu dass ich z.T. sehr lange Konstruktoren für die anderen Klassen habe. Das sieht nicht gut aus und ist auch nicht übersichtlich. Gibt es da bessere Varianten?
Weiterhin würde ich gerne wissen, wie man sicher mit Passwörtern im Sinne dieser Client-Server-Geschichte arbeiten kann.
Ich dachte mir das so: Client schickt password - Server prüft Passwort - Server sendet richtig/falsch.
Ohne dass sowas eventuell mitgesnifft werden kann (quasi Verschlüsselung usw.).
Sorry für die Wall-of-Text und danke für eure Hilfe,
Bolty
ich habe mich zuletzt recht intensiv mit java.net.* und der Server-Client-Entwicklung beschäftigt.
Als kleinen Test für mich selbst habe ich dann ein Client-Server-basiertes Chatprogramm für mehrere Clients für die Kommandozeile entwickelt, welches auch gut funktioniert hat, aber dennoch sehr simpel war.
Jetzt möchte ich das ganze verbessern, indem ich für den Server und den Client eine graphische Oberfläche entwickle und der User sich zudem mit einem Nickname und weiteren Daten anmelden kann usw.
Zu diesem Zweck möchte ich, dass der Client direkt nach dem verbinden über einen ObjectStream die von mir erstellte Klasse ClientInfo überträgt (werde ich jetzt hier nicht posten, enthält nur ein paar Attribute sowie getter und setter).
Nun bin ich mir nicht sicher, wie ich das realisieren soll; im Grunde wird jeder Client der sich verbindet in einem Thread gehandlet.
Derzeit habe ich folgende Klassen:
serverFrame = grafische Oberfläche, beinhaltet keinen relevanten Code
Server = extends Thread, läuft in Endlosschleife um eingehen Verbindungen anzunehmen.
ClientListener = extends Thread, für jede neue Verbindung (jeden neuen Socket) wird diese Klasse neu instanziert. Hier wird auf das eintreffen des ObjectStreams und dann im Anschluss auf eingehende Nachrichten gewartet.
Mein Problem: Wenn sich ein Client verbindet, aber kein ClientInfo im Anschluss sendet, läuft der Thread ewig weiter und wartet auf einen ObjectStream, ohne eine Möglichkeit diesen beenden zu können. Wie kann ich dieses Problem lösen?
Dieses Problem tritt z.B. auf, wenn ich versuche mit dem alten Kommandozeilenprogramm zu verbinden. Die Verbindung klappt, allerdings erhält der Server dann natürlich kein Object.
Hier der run-Methode der Server-Klasse:
Java:
public synchronized void run()
{
try
{
addLogEntry("Starte Server auf Port " + mPort);
mServerSocket = new ServerSocket(mPort);
addLogEntry("Server gestartet, Clients können sich verbinden.");
mServerDispatcher = new ServerDispatcher(mClients);
/*
* Endlosschleife um Clientanfragen zu bearbeiten.
* Wenn ein Client angenommen wurde, wird ein Object (ClientInfo)
* erwartet. Nach einer gewissen Wartezeit ohne gültiges Objekt
* soll der Client verworfen werden. Kommt ein gültiges Objekt an, wird
* dieses in den Clients-Vektor gespeichert.
*
* mClients = Vector, der alle ClientInfos enthält.
* mMaxUsers = int zum prüfen der maximalen Useranzahl
*/
while(true)
{
try
{
Socket newClient = mServerSocket.accept();
if(mClients.size() <= mMaxUsers)
{
ClientListener newClientInfo = new ClientListener(newClient, mClients);
newClientInfo.start();
addLogEntry("Neuer User verbunden");
}
}
catch(Exception e)
{
addLogEntry("User hat versucht sich zu verbinden, ist aber fehlgeschlagen.");
}
}
}
catch (IOException ex)
{
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
Und hier die run-Methode der ClientListener-Klasse:
Java:
public synchronized void run()
{
try
{
ObjectInputStream in = new ObjectInputStream(mClient.getInputStream());
Object o = in.readObject();
if(o instanceof ClientInfo)
{
mClientInfo = (ClientInfo)o;
mClientInfo.setConnection(mClient);
mClients.add((ClientInfo)o);
in.close();
try {
while (!isInterrupted()) {
try {
String message = mSocketReader.readLine();
if (message == null)
break;
mServerMessageHandler.sendMessage(message);
}
catch (SocketTimeoutException ste)
{
}
}
} catch (IOException ioex) {
}
}
else
mClient.close();
}
catch (IOException ex)
{
Logger.getLogger(ClientListener.class.getName()).log(Level.SEVERE, null, ex);
}
catch (ClassNotFoundException ex)
{
Logger.getLogger(ClientListener.class.getName()).log(Level.SEVERE, null, ex);
}
}
Dies wäre eigentlich meine Hauptfrage.
Ansonsten hätte ich noch zwei nebensächliche: Dieses Projekt ist bisher das größte, an dem ich bisher gearbeitet habe, und mir gefällt die Art meiner Programmierung nicht bzw. ich weiß nicht wie ich sie besser machen könnte.
Im Grunde ist ja alles von der serverFrame-Klasse abhängig. Dort werden die Vectoren für die Clients initialisiert und noch einige andere Variablen.
Diese muss ich natürlich weitergeben. Allein die Klasse mClients (ein Vector, der alle ClientInfos hält) wird vom ServerFrame an die Klasse Server weitergegeben, von da an die Klasse ClientListener usw. So kommt es dazu dass ich z.T. sehr lange Konstruktoren für die anderen Klassen habe. Das sieht nicht gut aus und ist auch nicht übersichtlich. Gibt es da bessere Varianten?
Weiterhin würde ich gerne wissen, wie man sicher mit Passwörtern im Sinne dieser Client-Server-Geschichte arbeiten kann.
Ich dachte mir das so: Client schickt password - Server prüft Passwort - Server sendet richtig/falsch.
Ohne dass sowas eventuell mitgesnifft werden kann (quasi Verschlüsselung usw.).
Sorry für die Wall-of-Text und danke für eure Hilfe,
Bolty
Zuletzt bearbeitet: