WebSockets в Kotlin: Создаем real-time приложения с нуля

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

WebSockets в Kotlin: от теории к real-time магии

Представьте, что вы открыли мессенджер, отправили сообщение — и оно мгновенно появилось у собеседника. Без перезагрузки страницы, без постоянных запросов к серверу. Это не магия, это WebSockets в Kotlin. Если вы когда-нибудь хотели создать свой чат, систему уведомлений в реальном времени или многопользовательскую игру — вы пришли по адресу.

В этой статье мы разберем, как работают WebSockets, напишем полноценное real-time приложение на Kotlin с использованием Ktor, и я покажу вам код, который можно сразу запустить. Поехали!

Что такое WebSockets и почему они нужны в Kotlin?

WebSocket — это протокол двунаправленной связи между клиентом и сервером поверх одного TCP-соединения. В отличие от классического HTTP, где клиент всегда инициирует запрос, WebSocket позволяет серверу самому отправлять данные клиенту в любой момент.

Чем WebSocket лучше HTTP?

  • Мгновенность: данные доставляются за миллисекунды
  • Экономия трафика: нет лишних заголовков, как в HTTP
  • Двунаправленность: сервер может инициировать отправку
  • Постоянное соединение: не нужно переустанавливать каждый раз

Kotlin с его корутинами и фреймворком Ktor идеально подходит для работы с WebSockets. Асинхронность, легковесность и выразительный синтаксис — вот что делает Kotlin WebSocket разработку такой приятной.

Когда использовать WebSockets?

Вот несколько сценариев, где real-time приложения на Kotlin с WebSockets будут незаменимы:

  • Чаты и мессенджеры — передача сообщений в реальном времени
  • Системы уведомлений — алерты, всплывающие окна, обновления статусов
  • Онлайн-игры — синхронизация игроков
  • Биржевые котировки — обновление цен без перезагрузки
  • Совместное редактирование — Google Docs-like функционал

Настройка проекта: Ktor + WebSockets

Для создания WebSocket сервера на Kotlin мы будем использовать Ktor — современный асинхронный фреймворк от JetBrains. Давайте настроим проект.

Шаг 1: Добавляем зависимости

Если вы используете Gradle (а я уверен, что используете), добавьте в build.gradle.kts:

dependencies {
    implementation("io.ktor:ktor-server-core:2.3.7")
    implementation("io.ktor:ktor-server-netty:2.3.7")
    implementation("io.ktor:ktor-server-websockets:2.3.7")
    implementation("ch.qos.logback:logback-classic:1.4.14")
}

Шаг 2: Создаем WebSocket сервер

Теперь напишем сам сервер. Он будет принимать подключения и транслировать сообщения всем подключенным клиентам — базовая логика чата.

import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.websocket.*
import io.ktor.websocket.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch

fun main() {
    val clients = mutableSetOf<WebSocketSession>()

    embeddedServer(Netty, port = 8080) {
        install(WebSockets) {
            pingPeriod = 15_000 // 15 секунд
            timeout = 15_000
            maxFrameSize = Long.MAX_VALUE
        }

        routing {
            webSocket("/chat") {
                // Добавляем клиента
                clients.add(this)
                println("Новое подключение: $this")

                try {
                    for (frame in incoming) {
                        if (frame is Frame.Text) {
                            val message = frame.readText()
                            println("Получено: $message")

                            // Отправляем всем клиентам
                            clients.forEach { client ->
                                client.send(Frame.Text("$message"))
                            }
                        }
                    }
                } catch (e: Exception) {
                    println("Ошибка: ${e.message}")
                } finally {
                    // Удаляем клиента при отключении
                    clients.remove(this)
                    println("Подключение закрыто: $this")
                }
            }
        }
    }.start(wait = true)
}

Этот код создает простой WebSocket чат на Kotlin. Все сообщения, отправленные одним клиентом, видят все остальные. Обратите внимание на использование корутин — они делают код неблокирующим и эффективным.

Написание WebSocket клиента на Kotlin

Сервер готов, но без клиента он бесполезен. Давайте напишем WebSocket клиент на Kotlin с помощью Ktor Client.

Шаг 1: Добавляем клиентскую зависимость

implementation("io.ktor:ktor-client-websockets:2.3.7")
implementation("io.ktor:ktor-client-cio:2.3.7")

Шаг 2: Код клиента

import io.ktor.client.*
import io.ktor.client.plugins.websocket.*
import io.ktor.websocket.*
import kotlinx.coroutines.*

suspend fun main() {
    val client = HttpClient {
        install(WebSockets)
    }

    client.webSocket("ws://localhost:8080/chat") {
        // Запускаем корутину для чтения сообщений
        launch {
            for (frame in incoming) {
                if (frame is Frame.Text) {
                    println("Сервер: ${frame.readText()}")
                }
            }
        }

        // Отправляем сообщения
        send(Frame.Text("Привет, мир!"))
        delay(1000)
        send(Frame.Text("Как дела?"))
        delay(1000)
        send(Frame.Text("Пока!"))

        // Ждем немного перед закрытием
        delay(2000)
    }

    client.close()
}

Этот клиент подключается к нашему серверу, отправляет несколько сообщений и выводит ответы. Просто, правда?

Продвинутые техники: аутентификация и комнаты

В реальных проектах простой чат — это только начало. Давайте посмотрим, как добавить аутентификацию и комнаты (channels) для групповых чатов.

Аутентификация через WebSocket

При подключении к WebSocket можно передать токен в query-параметре:

webSocket("/chat?token={token}") {
    val token = call.parameters["token"]
    if (token == null || !isValidToken(token)) {
        close(CloseReason(CloseReason.Codes.VIOLATED_POLICY, "Неверный токен"))
        return@webSocket
    }
    // ... остальная логика
}

Создание комнат

Чтобы разделить пользователей на комнаты, можно использовать Map:

val rooms = mutableMapOf<String, MutableSet<WebSocketSession>>()

webSocket("/chat/{room}") {
    val roomName = call.parameters["room"] ?: "general"
    val room = rooms.getOrPut(roomName) { mutableSetOf()                

Блоги

Рекомендаций по книгам