Introduction to WebSocket in Kotlin: from theory to real-time practice
Modern web applications increasingly require instant data exchange between client and server. The traditional HTTP protocol, operating on a "request-response" principle, is not suitable for tasks where information must arrive in real time: online chats, stock quotes, multiplayer games, or push notifications. This is where WebSocket comes to the rescue — a protocol that provides a permanent two-way connection.
Kotlin, being a modern language for JVM, JavaScript and Native, provides excellent tools for working with WebSocket. In this article, we will look at how to create real-time applications in Kotlin using the Ktor library — a popular framework for building asynchronous servers and clients. You will learn how to set up a WebSocket connection, send and receive messages, handle errors, and build scalable solutions.
1. WebSocket basics: why Kotlin and Ktor?
WebSocket is a protocol that, after establishing a connection via an HTTP handshake, switches the channel to a permanent two-way mode. Unlike HTTP, the server can initiate data sending without a client request. This is ideal for real-time scenarios.
Kotlin paired with Ktor offers:
- Asynchrony — Kotlin coroutines allow handling thousands of simultaneous connections without blocking threads.
- Cross-platform — the same code can run on JVM, JavaScript and Native.
- Conciseness — minimum boilerplate, maximum expressiveness.
- Security — built-in support for SSL/TLS, authentication and CORS.
Let's move on to practice and create a simple WebSocket server and client in Kotlin.
2. Creating a WebSocket server in Kotlin with Ktor
2.1. Project setup
First, create a new Gradle or Maven project. Add Ktor dependencies to 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("ch.qos.logback:logback-classic:1.4.11")}2.2. Server implementation
Let's create a WebSocket server that accepts connections, reads messages and responds to them. The example below uses the Ktor library with coroutines:
import io.ktor.server.engine.*import io.ktor.server.netty.*import io.ktor.server.websocket.*import io.ktor.websocket.*import kotlinx.coroutines.delay
fun main() { embeddedServer(Netty, port = 8080) { install(WebSockets) webSocket("/chat") { send(Frame.Text("Welcome to the chat!")) for (frame in incoming) { if (frame is Frame.Text) { val text = frame.readText() println("Received: $text") send(Frame.Text("Echo: $text")) } } } }.start(wait = true)}Here we:
- Install the
WebSocketsplugin. - Define the
/chatendpoint. - Process incoming frames in a coroutine and send an echo response.
2.3. Error handling and connection closing
In real applications, it is important to correctly handle connection breaks. Let's add exception handling and session closing:
webSocket("/chat") { try { send(Frame.Text("Connection established")) for (frame in incoming) { when (frame) { is Frame.Text -> { val text = frame.readText() if (text.equals("exit", ignoreCase = true)) { cl