Socket Handshake

Eldorado

Bekanntes Mitglied
Hi Leute,

ich bin grad (für die Schule, ist aber keine Hausaufgabe! (arbeite schon mal etwas vor raus)) einen Kleinen Chat am Programmieren. Jetzt habe ich mich etwas in der "Authentifizierung" verrannt:

1. Server und Client senden 0x6b bis beide dies empfangen haben
3. Client sendet gewünschten Nickname
4. Ist der Name frei wird 0x6e, ist er belegt 0x6f
5. Schritt 4 wird solange wiederholt, bis ein Nickname festgelegt wurde => 0x6e

...Jetzt würde ich gerne Wissen, ob der Client die Bestätigung korrekt empfangen hat, kann ja aber nicht auf eine Besttätigung vom Client warten (logische Schleife...(Wo wir doch kurz Fastnacht sind: Songtext: Medium Terzett - Ein Loch ist im Eimer Lyrics))

Die Lösung wird wahrscheinlich ganz banal sein oder es wird rauskommen, dass ich es sowieso komplett umständlich gemacht habe. Ich möchte durch das System halt sicher gehen, dass immer beide Seiten über den aktuellen Status informiert sind. Die "Steuerzeichen" sind übrigens einfach aus der Luft gegriffen.

Also nochmal zusammenfassend: Wie stelle ich es an, dass der Client weiß, dass ein Nickname akzeptiert wurde und der Server weiß, dass der Client dies weiß.

Gruß
Eldorado
 

Michael...

Top Contributor
Also nochmal zusammenfassend: Wie stelle ich es an, dass der Client weiß, dass ein Nickname akzeptiert wurde und der Server weiß, dass der Client dies weiß.
Ganz banal ausgedrückt: Indem der Server den Client sagt, dass er den Nickname aktzeptiert hat und der Client darauf antwortet, dass er verstanden hat, dass der Server den Nickname aktzeptiert hat.

Wobei sich generell die Frage stellt: Warum? Oder wovor hast Du Angst?
 

Eldorado

Bekanntes Mitglied
Dass einer von beiden darauf wartet, dass der andere was schickt, es aber geschickt wurde, bevor er darauf gewartet hat...
Ich mach das so, dass ich in einer Schleife solange Pakete schicke, bis der andere Antwortet (da ich nur dann sicher sein kann, dass der InputStream zu diesem Zeitpunkt wo ich schicke "abgehört" wurde)
 

Michael...

Top Contributor
Dass einer von beiden darauf wartet, dass der andere was schickt, es aber geschickt wurde, bevor er darauf gewartet hat...
Ich mach das so, dass ich in einer Schleife solange Pakete schicke, bis der andere Antwortet (da ich nur dann sicher sein kann, dass der InputStream zu diesem Zeitpunkt wo ich schicke "abgehört" wurde)
??? Warum sollen die wahllos Daten durchs Netz schiessen?

Normalerweise läuft das doch eher so ab:
(Server ist gestartet)
(Irgendwann) verbindet sich ein Client zum Server
Der Server sendet eine Nachricht zum Client: Authentifiziere Dich oder Registriere Dich als neuer Nutzer
Client: Ich möchte mich als XY registieren
Server: XY ist schon vergeben
Client: Ich möchte mit als AB registrieren
Server: Herzlich willkommen AB

Allerdings würde ich das ersteinmal hinten anstellen und versuchen eine Kommunikation ohne Registrierung (man kann ja vorher Usernamen und PWD festlegen) aufzubauen.
 

Eldorado

Bekanntes Mitglied
Sorry, ich hatte da etwas total missverstanden. Hatten vorher serielle Schnittstellen programmiert, da brauchte man irgendwie so Krücken...naja^^

Danke für die Erleuchtung :)
 

Eldorado

Bekanntes Mitglied
Aber irgendwie scheine ich trotzdem noch irgendwas falsch zu machen:
Server (der angenommene Client ist eine Instanzvariable (socket))
Java:
 private void authenticate() {
        BufferedReader inputStream = null;
        OutputStreamWriter outputStream = null;
        try {
            inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            outputStream = new OutputStreamWriter(socket.getOutputStream());

            log.debug("authentificate user");

            outputStream.write(0x6b);

            String username = null;
            while (username == null && !socket.isClosed()) {
                try {
                    username = inputStream.readLine();
                } catch (SocketTimeoutException e) { //Gerät hier in den Timeout, da er keine Nachricht vom Client erhält
                } catch (IOException ex) {
                    log.error("Cannot read username", ex);
                }
                if (username != null && userPool.isNameAbavaible(username)) {
                    try {
                        userPool.addUser(new StandartUser(username, socket.getInetAddress()));
                    } catch (UserNameInUseException ex) {
                        log.error(ex);
                    }
                    outputStream.write(0x6e);
                } else {
                    outputStream.write(0x6f);
                    username = null;
                }
            }
        } catch (IOException ex) {
            log.error("Connection error", ex);
        }
    }

Client:
Java:
private void authenticate(String nickname) throws UserNameInUseException {
        InputStreamReader inputStream = null;
        BufferedWriter outputStream = null;
        try {
            inputStream = new InputStreamReader(socket.getInputStream());
            outputStream = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

            if (inputStream.read() == 0x6b) {  //read blockt, scheint aber keine Nachricht zu erhalten und dadurch geht es nicht weiter

                outputStream.write(nickname);

                int answer = inputStream.read();
                
                if (answer == 0x6f) {
                    throw new UserNameInUseException(nickname);
                } else if (answer == 0x6e) {
                    log.info("Connection with nickname " + nickname + "establisht");
                }

            }
        } catch (IOException ex) {
            log.error("Connection error", ex);
        }
    }

Das ist jetzt nur eine grobe Struktur. Aber ich scheine ja irgendwas falsch zu machen... :)
 

Michael...

Top Contributor
Warum sowas:
Code:
outputStream.write(0x6b);
Wie reagiert der Client darauf? Vermutlich garnicht.
Da kann es durch aus sein, dass der Server sich an der Stelle
Code:
inputStream.readLine();
zu Tode wartet.

Dir scheint die Kommunikation via Socket noch nicht ganz klar zu sein. Hab jetzt leider keine einfache Demo zur Hand, sonst hätte ich diese gepostet. (HIer bzw. im Netz sollte sich was finden lassen)
Du solltest Dich auf ein Protokoll festlegen, entweder auf Byte Basis oder String basierend.
Das Lesen und Schreiben vom Input bzw. in den OutputStream sollten auf Client und Server Seite in separaten Threads ablaufen.
 

Eldorado

Bekanntes Mitglied
OK. dann schaue ich nochmal. Ich mache es dann aber gleich als ObjectStream, weil die Nachrichten später auch als Objekte gesendet werden sollen. Das soll später die Möglichkeit offen halten noch mehr Informationen in die Nachricht zu packen ohne auf beiden Seiten groß parsen zu müssen.

Folgender Ablauf:
1. Server wartet auf Client
2. Client stellt Verbindung her
3. Client sendet ein Objekt mit dem Benutzernamen
4. Server sendet ein Objekt mit der Antwort (Name verfügbar oder eben nicht)
5. Normales warten auf Nachrichten

Aber warum in extra Threads? Der Thread der diese Methode aufruft (ist natürlich ein andere Thread, als der, der auf Anfragen wartet) sendet ja nur einmal Daten (das passiert ja sofort und ohne den Thread lange zu blockieren) und dann wird auf eine Antwort gewartet, was zu einer Blockierung führt, aber diese ist ja gewollt...Also ich weiß nicht warum ich das Senden in einen extra Thread packen sollte.

Werde das voraussichtlich heute Nachmittag angehen.

Danke für deine Unterstützung.
 

Michael...

Top Contributor
Im Falle der Anmeldung bzw. Registierung hast Du eine sequentielle Kommunikation zwischen Client und Server. Hier ist die Kommunikation getrennt in einzelnen Threads nicht unbedingt notwendig.

Aber letztendlich soll daraus ja ein Chat werden. Hier wird dann ja parallel gesendet und empfangen und solch eine sequentielle Kommunikation würde letztendlich blockieren. (z.B. User am Client will senden, muss aber warten, da noch ein readline() den Thread blockiert)
 

Eldorado

Bekanntes Mitglied
Das ist klar, da haben wir an einander vorbei geredet.

Sobald die Anmeldung abgeschlossen ist, wird ein Thread gestartet, der ankommende Nachrichten abwartet, diese in einen "MessagePool" schmeißt, dort wird ein Event (neue Nachricht) gefeuert und daraufhin schicken die Listener die Nachricht an die Clients.

Das ist soweit auch fertig und sollte eigentlich auch funktionieren, nur hänge ich halt einen Schritt davor :)
 

Eldorado

Bekanntes Mitglied
So läuft jetzt alles. Ein Problem hatte ich noch:
Initialisiert man einen ObjectOutputStream muss auf der anderen Seite des Streams der ObjectInputStream geöffnet werden. Da wird ein eigenes Protokoll verwendet,deswegen blockiert er da. Das heißt im Praktischen: Auf dem Server initialisiere ich zuerst den ObjectInputStream und dann den ObjectOutputStream und auf dem Client erst den ObjectOutputSream und dann den ObjectInputStream. (Nur falls jemand diesen Thread findet und diese Problem hat)

Nochmal Danke für die Unterstützung.
 
Ähnliche Java Themen

Ähnliche Java Themen


Oben