WebSocket библиотека Kotlin: ktor-client-websockets для реального времени

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

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

Начать курс

WebSocket библиотека Kotlin: ktor-client-websockets

В современной веб-разработке всё чаще требуется обмен данными в реальном времени: онлайн-чаты, уведомления, биржевые котировки, многопользовательские игры. Для Kotlin одной из самых мощных и нативных библиотек для работы с протоколом WebSocket является ktor-client-websockets — часть экосистемы Ktor (Kotlin HTTP-клиент).

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

Что такое WebSocket и зачем он нужен?

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

  • чатов и мессенджеров;
  • уведомлений и ленты событий;
  • игр и коллаборативных редакторов;
  • финансовых тикеров и трейдинга.

Установка библиотеки ktor-client-websockets

Для начала добавьте зависимость в ваш build.gradle.kts (проект на Kotlin/JVM или Kotlin Multiplatform).

// build.gradle.kts
dependencies {
    implementation("io.ktor:ktor-client-core:2.3.7")
    implementation("io.ktor:ktor-client-cio:2.3.7") // или другой движок
    implementation("io.ktor:ktor-client-websockets:2.3.7")
}

Если вы используете Kotlin Multiplatform, убедитесь, что добавили модуль для каждой платформы (например, ktor-client-okhttp для Android).

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

Основной класс для работы с WebSocket — HttpClient с плагином WebSockets. Рассмотрим простейший пример подключения к WebSocket-серверу.

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

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

    client.webSocket("ws://echo.websocket.org") {
        // Отправляем сообщение
        send(Frame.Text("Привет, WebSocket!"))

        // Получаем ответ
        for (frame in incoming) {
            when (frame) {
                is Frame.Text -> {
                    println("Получено: ${frame.readText()}")
                }
                else -> println("Другой тип фрейма: $frame")
            }
        }
    }

    client.close()
}

В этом коде мы:

  1. Создаём HTTP-клиент с поддержкой WebSocket.
  2. Устанавливаем соединение с тестовым сервером ws://echo.websocket.org.
  3. Отправляем текстовое сообщение.
  4. Читаем входящие фреймы и выводим их в консоль.

Обработка ошибок и закрытие соединения

В реальных приложениях важно корректно обрабатывать исключения и закрывать соединение. Используйте try-catch и finally.

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

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

    try {
        client.webSocket("ws://your-server.com/ws") {
            // Отправка
            send(Frame.Text("Пинг"))

            // Приём с таймаутом
            withTimeout(5000) {
                for (frame in incoming) {
                    if (frame is Frame.Text) {
                        println("Ответ: ${frame.readText()}")
                    }
                }
            }
        }
    } catch (e: Exception) {
        println("Ошибка WebSocket: ${e.message}")
    } finally {
        client.close()
    }
}

Продвинутые возможности: фильтрация фреймов и пинг/понг

Библиотека поддерживает не только текстовые, но и бинарные фреймы (Frame.Binary), а также пинг-понг для поддержания соединения. Вы можете фильтровать типы фреймов:

client.webSocket("ws://example.com/ws") {
    for (frame in incoming) {
        when (frame) {
            is Frame.Text -> {
                println("Текст: ${frame.readText()}")
            }
            is Frame.Binary -> {
                println("Бинарные данные: ${frame.readBytes().size} байт")
            }
            is Frame.Ping -> {
                println("Пинг получен, отправляем понг")
                send(Frame.Pong(frame.data))
            }
            else -> {
                println("Другой фрейм: $frame")
            }
        }
    }
}
                
    
    

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