Ich habe mich doch entschieden, einige Umbauten durchzuführen. Zunächst wollte ich den Server eigentlich pro Verbindung mit einem Thread laufen lassen. Das hat direkt, für ein Hobbyprojekt mit wenig Zeit, viele Probleme aufgeworfen.
Von Threads
Vor allem sind die Dateideskriptoren auf unterschiedlichen Betriebssystemen unterschiedlich konfiguriert, aber doch teils sehr limitiert. Ich wollte auf meinem Mac mal eben 500 Verbindungen aufbauen, bei 80 oder so war Schluss. Man kann das Limit zwar höher schrauben, aber man ist natürlich durchaus limitiert.
Dann gab es noch Probleme mit dem Verschieben von Objekten innerhalb von Qt zu Threads. Neue erstellte Objekte liefen nicht im Thread, sondern Hauptthread. Das kann man alles recht problemlos fixen, indem man mit Workerprozessen arbeitet, aber ich wollte da nicht weiter herumbauen (zeitliche Einschränkung), da ich vorwärts kommen wollte. Aber interessant: Ich habe mal 500 Konnektierungen gleichzeitig startet (so gleichzeitig, wie es nur geht). Das hat auf meinem Mac 200ms (etwas darunter) benötigt, um auf 500 Verbindungen ein “Hallo Welt” über das Loopback-Device zu senden. War zwar nur Loopback, aber ich war doch erstaunt, wie schnell es geht, so viele Threads zu öffnen, was zu schicken und wieder zu schließen.
Keine Threads mehr
Dann habe ich einfach mit generellen nonblocking Sockets herumgespielt (im Thread waren sie auch nonblocking!) und festgestellt, dass es von der Geschwindigkeit her für einige hundert Verbindungen ausreichen sollte, zumal man nicht sonderlich viele Informationen senden muss und diese ja auch noch komprimieren kann. Also habe ich alles umgebaut.
Benutzerauthentifizierung
Ich habe das tatsächlich so ähnlich, wie im vorherigen Blogeintrag, implementiert. Letztlich ist es so: Der Client macht eine Authentifizierungsanforderung an den Server. Der Server kennt den Benutzernamen und schickt eine UUID. Dann werden die Benutzerinformationen mit der UUID zusammengefasst und gehasht, zurückgeschickt, der Server macht das selbe und vergleicht beide Ergebnisse. Sind sie gleich, gilt der Benutzer als eingeloggt.
Weiteres
Weiterhin habe ich noch Datenbankabstraktionen implementiert für MySQL, PostgreSQL und SQLite, damit man Benutzer speichern kann. Ein Logging habe ich implementiert und dem Server kann man Signale schicken, um ihn zu beenden oder sonst was zu tun. Es gibt einen Testclient unter resources/sslclient, mit dem man mit dem Server ein wenig spielen kann.
Hier geht es übrigens zum GitHub-Repo.