WebSocket auf Kotlin: Erstellung von Echtzeit-Anwendungen auf fortgeschrittenem Niveau

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum fortgeschrittenes WebSocket auf Kotlin?

\n

Moderne Webanwendungen erfordern zunehmend eine sofortige Datenübertragung: Chats, Benachrichtigungen, Online-Spiele, Finanzkurse und Dashboards. Das grundlegende WebSocket-Protokoll ermöglicht die Einrichtung einer permanenten bidirektionalen Verbindung zwischen Client und Server, aber in der Praxis erfordert die Entwicklung einer zuverlässigen und skalierbaren Echtzeit-Anwendung auf Kotlin weit mehr als nur das Öffnen eines Sockets.

\n

In diesem Artikel gehen wir über einen einfachen Echo-Server hinaus. Wir betrachten Architekturmuster für die Arbeit mit Tausenden von Verbindungen, Fehlerbehandlung mit Kotlin-Koroutinen, Server-Clusterbildung mit Message-Brokern und Sicherheitsaspekte. Das Material richtet sich an Entwickler, die bereits mit den Grundlagen von Kotlin und Ktor vertraut sind.

\n\n

1. Architektur eines hochlastigen WebSocket-Servers mit Ktor

\n

Für eine Produktionslösung reicht es nicht aus, einfach einen webSocket-Handler zu installieren. Es müssen die Sitzungsverwaltung, der Lebenszyklus der Verbindung und die Isolierung der Handler durchdacht werden. Betrachten wir die Schlüsselelemente.

\n\n

Sitzungsverwaltung und deren Gruppierung

\n

Jede WebSocket-Verbindung in Ktor wird durch ein Objekt DefaultWebSocketSession dargestellt. Zum Senden von Nachrichten an einen bestimmten Benutzer oder eine Gruppe (z. B. "Chatraum") müssen aktive Sitzungen gespeichert werden. Verwenden Sie ConcurrentHashMap für die Threadsicherheit.

\n
import io.ktor.websocket.*\nimport java.util.concurrent.ConcurrentHashMap\n\nclass SessionManager {\n    private val sessions = ConcurrentHashMap<String, WebSocketSession>()\n    private val roomSessions = ConcurrentHashMap<String, MutableSet<String>>()\n\n    fun addUserToRoom(roomId: String, userId: String, session: WebSocketSession) {\n        sessions[userId] = session\n        roomSessions.computeIfAbsent(roomId) { mutableSetOf() }.add(userId)\n    }\n\n    suspend fun broadcastToRoom(roomId: String, message: String) {\n        roomSessions[roomId]?.forEach { userId ->\n            sessions[userId]?.send(Frame.Text(message))\n        }\n    }\n\n    fun removeUser(userId: String) {\n        sessions.remove(userId)\n        roomSessions.forEach { (_, users) -> users.remove(userId) }\n    }\n}
\n\n

Lebenszyklusverwaltung mit Koroutinen

\n

Ktor verwendet Koroutinen zur Verarbeitung jeder Verbindung. Es ist wichtig, Ausnahmen und das Schließen des Sockets korrekt zu behandeln, um Speicherlecks zu vermeiden. Verwenden Sie try-catch innerhalb des webSocket-Blocks und rufen Sie removeUser im finally-Block auf.

\n
install(WebSockets) {\n    pingPeriod = Duration.ofSeconds(15)\n    timeout = Duration.ofSeconds(30)\n    maxFrameSize = Long.MAX_VALUE\n    masking = false\n}\n\nembeddedServer(Netty, port = 8080) {\n    val sessionManager = SessionManager()\n    routing {\n        webSocket("/chat/{roomId}") {\n            val roomId = call.parameters["roomId"] ?: "general"\n            val userId = call.request.queryParameters["userId"] ?: "anon"\n            sessionManager.addUserToRoom(roomId, userId, this)\n            try {\n                for (frame in incoming) {\n                    if (frame is Frame.Text) {\n                        val text = frame.readText()\n                        sessionManager.broadcastToRoom(roomId, "[$userId]: $text")\n                    }\n                }\n            } catch (e: Exception) {\n                log.error("WebSocket-Fehler für Benutzer $userId: ${e.localizedMessage}")\n            } finally {\n                sessionManager.removeUser(userId)\n                log.info("Benutzer $userId hat den Raum $roomId verlassen")\n            }\n        }\n    }\n}.start(wait = true)
\n\n

2. Skalierung und Clusterbildung von WebSocket auf Kotlin

\n

Ein einzelner Server wird mit Zehntausenden gleichzeitigen Verbindungen nicht fertig. Die Lösung ist horizontale Skalierung. Allerdings "lebt" die WebSocket-Verbindung

Blogs

Buchempfehlungen