WebSocket is a protocol that provides a full-duplex communication session between the user's browser and a server over a single TCP connection. It is particularly useful for creating applications that require real-time data transfer from and to the server.
Introduction
WebSockets shine in scenarios that require real-time communication. For example, they are widely used in chat applications, online multiplayer games, and real-time data dashboards.
For a mobile application, WebSockets enable seamless interaction with a backend server, allowing mobile clients to maintain a live link to the server for push notifications or updates. In mobile development, WebSockets are useful for building apps where timely delivery of message updates is critical, such as collaborative editing tools or live sports score apps.
If you are new to WebSockets, we recommend reading our Web - WebSocket overview first.
Server
To use WebSockets, you need to include the ktor-server-websockets dependency:
dependencies: - $ktor.server.websocketsInstall the WebSockets plugin by passing it to the install function within your application module:
import io.ktor.server.application.*import io.ktor.server.websocket.*// ...fun Application.module() { install(WebSockets) // ...}Configure WebSockets
You can customize the plugin’s behavior within the install block using WebSocketOptions:
pingPeriod: Frequency of keep-alive pings.timeout: Duration after which an inactive connection is closed.maxFrameSize: Maximum size allowed for a single frame.masking: Whether to enable frame masking.contentConverter: A converter for automated serialization and deserialization.
install(WebSockets) { pingPeriod = 15.seconds timeout = 15.seconds maxFrameSize = Long.MAX_VALUE masking = false}Handle WebSockets sessions
Define a WebSocket endpoint by calling the webSocket function inside your routing block:
routing { webSocket("/echo") { // Handle a WebSocket session }}With the default configuration, this server accepts requests at ws://localhost:8080/echo.
Inside the block, the session is represented by DefaultWebSocketServerSession.
Key properties and functions include:
send(): Sends text or binary content to the client.incoming: A channel for receiving frames from the client.outgoing: A channel for sending frames to the client.close(): Terminate the session with a specific reason.
Frames are typically handled by checking their type:
Frame.Text: Read content usingreadText().Frame.Binary: Read content usingreadBytes().
Example: Handle a single session
This example demonstrates a basic echo handler that greets the user and closes the connection when they say “bye”:
routing { webSocket("/echo") { send("Please enter your name") for (frame in incoming) { frame as? Frame.Text ?: continue val receivedText = frame.readText() if (receivedText.equals("bye", ignoreCase = true)) { close(CloseReason(CloseReason.Codes.NORMAL, "Client said BYE")) } else { send(Frame.Text("Hi, $receivedText!")) } } }}Download the websocat tool as explained in the Web - WebSocket overview.
Connect to your server:
.\websocat.exe ws://localhost:8080/echoPlease enter your namedavidHi, davidAlso, you can test with an http file on Idea like this:
Example: Handle multiple sessions
To efficiently manage multiple WebSocket sessions and handle broadcasting, you can use Kotlin’s SharedFlow.
This approach provides a scalable and concurrency-friendly method for managing WebSocket communications.
Define a SharedFlow for broadcasting messages:
val messageResponseFlow = MutableSharedFlow<MessageResponse>()val sharedFlow = messageResponseFlow.asSharedFlow()In your WebSocket route, implement the broadcasting and message handling logic:
webSocket("/broadcast") { send("You are connected to WebSocket!")
val job = launch { sharedFlow.collect { message -> send(message) } }
runCatching { incoming.consumeEach { frame -> if (frame is Frame.Text) { val message = frame.readText() messageResponseFlow.emit(message) } } }.onFailure { exception -> println("WebSocket exception: ${exception.localizedMessage}") }.also { job.cancel() }}The runCatching block processes incoming messages and emits them to the SharedFlow, which then broadcasts to all collectors.
By using this pattern, you can efficiently manage multiple WebSocket sessions without manually tracking individual connections. This approach scales well for applications with many concurrent WebSocket connections and provides a clean, reactive way to handle message broadcasting.
Open two or more terminals and open a websocket connection to your server on each terminal:
.\websocat.exe ws://localhost:8080/broadcastTo start a new session in a separate tab, click the Add button on the toolbar or press Ctr Shift T.
Test that messages sent from one client are received by all connected clients.