WebSocket библиотека Kotlin: Ktor WebSocket Client и Server

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

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

Начать курс

WebSocket библиотека Kotlin: Ktor WebSocket

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

В этой статье мы подробно разберём, как использовать WebSocket в Kotlin с помощью Ktor. Вы узнаете, как настроить зависимости, создать WebSocket сервер и клиент, отправлять и получать сообщения, а также обрабатывать ошибки и закрытие соединения.

Установка и настройка

Для начала работы добавьте необходимые зависимости в файл build.gradle.kts (или build.gradle). Если вы используете Gradle, подключите следующие модули:

// build.gradle.kts
dependencies {
    // Серверная часть
    implementation("io.ktor:ktor-server-core:2.3.0")
    implementation("io.ktor:ktor-server-netty:2.3.0")
    implementation("io.ktor:ktor-server-websockets:2.3.0")

    // Клиентская часть
    implementation("io.ktor:ktor-client-core:2.3.0")
    implementation("io.ktor:ktor-client-cio:2.3.0")
    implementation("io.ktor:ktor-client-websockets:2.3.0")
}

Для Maven используйте аналогичные артефакты. Все модули Ktor версии 2.x.x поддерживают Kotlin Coroutines и работают на JVM, Android, iOS и других платформах.

Создание WebSocket сервера на Ktor

Напишем простой эхо-сервер, который принимает сообщения от клиента и отправляет их обратно. Сервер будет слушать порт 8080.

import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.websocket.*
import io.ktor.websocket.*
import kotlinx.coroutines.*

fun main() {
    embeddedServer(Netty, port = 8080) {
        install(WebSockets)
        routing {
            webSocket("/chat") {
                send("Добро пожаловать в чат!")
                for (frame in incoming) {
                    if (frame is Frame.Text) {
                        val text = frame.readText()
                        println("Получено: $text")
                        send("Эхо: $text")
                    }
                }
            }
        }
    }.start(wait = true)
}

В этом примере:

  • install(WebSockets) — подключает плагин WebSocket к серверу.
  • webSocket("/chat") — определяет endpoint для подключения.
  • send() — отправляет сообщение клиенту.
  • incoming — канал, по которому приходят фреймы от клиента.
  • Фреймы могут быть текстовыми (Frame.Text), бинарными (Frame.Binary) или управляющими.

Создание WebSocket клиента на Ktor

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

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

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

    client.webSocket("ws://localhost:8080/chat") {
        // Читаем приветствие
        val welcome = incoming.receive() as Frame.Text
        println("Сервер: ${welcome.readText()}")

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

        // Ждём эхо-ответ
        val response = incoming.receive() as Frame.Text
        println("Сервер: ${response.readText()}")

        // Закрываем соединение
        close()
    }

    client.close()
}

Клиент использует движок CIO (Coroutine-based I/O) — он лёгкий и полностью асинхронный. Обратите внимание на ws:// — для защищённого соединения используйте wss://.

Расширенные возможности

Ktor WebSocket поддерживает не только текстовые, но и бинарные фреймы, пинги/понги, а также работу с сессиями. Вот несколько продвинутых примеров:

1. Обработка бинарных данных

webSocket("/binary") {
    for (frame in incoming) {
        if (frame is Frame.Binary) {
            val bytes = frame.readBytes()
            println("Получено ${bytes.size} байт")
            send(Frame.Binary(bytes)) // Отправляем обратно
        }
    }
}

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