I implemented a basic websockets server, following the instructions on the Ktor site (server, client).
Server (complete source):
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("Hi, $receivedText!")
while (true) {
send("1")
Thread.sleep(2000)
}
}
}
}
Client (complete source):
LaunchedEffect(deps.client) {
deps.socketsClient.webSocket(
method = HttpMethod.Get,
host = host,
port = 8080,
path = "/echo"
) {
val othersMessage = incoming.receive() as? Frame.Text
println(othersMessage?.readText())
send("somename")
val reply = incoming.receive() as? Frame.Text
println(reply?.readText())
for (frame in incoming) {
if (frame is Frame.Text) {
val number = frame.readText()
println("Received number: $number")
}
}
}
}
The server sends a ping to the client
2025-05-16 17:05:14.664 [eventLoopGroupProxy-3-3] TRACE io.ktor.websocket.WebSocket - WebSocket Pinger: sending ping frame
It works for a bit, then times out
2025-05-16 17:05:29.667 [eventLoopGroupProxy-3-5] TRACE io.ktor.websocket.WebSocket - WebSocket pinger has timed out
On the desktop client:
Exception in thread "AWT-EventQueue-0" java.io.EOFException at okio.RealBufferedSource.require(RealBufferedSource.kt:223) at okio.RealBufferedSource.readByte(RealBufferedSource.kt:233) at okhttp3.internal.ws.WebSocketReader.readHeader(WebSocketReader.kt:119) at okhttp3.internal.ws.WebSocketReader.processNextFrame(WebSocketReader.kt:102) at okhttp3.internal.ws.RealWebSocket.loopReader(RealWebSocket.kt:293) at okhttp3.internal.ws.RealWebSocket$connect$1.onResponse(RealWebSocket.kt:195) at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.base/java.lang.Thread.run(Unknown Source) Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.ui.scene.ComposeContainer$DesktopCoroutineExceptionHandler@73344c2d, androidx.compose.runtime.BroadcastFrameClock@24265a26, StandaloneCoroutine{Cancelling}@783b937, FlushCoroutineDispatcher@7dacd0c]
The iOS (Darwin engine) client has the same problem.
Here's the complete Compose Multiplatform project where it can be reproduced.
Note that to run on iOS it currently requires to set the Kotlin version to 2.1.10
and uncomment the skie
plugin (here)
Any ideas?
i checked your codes
now it will ok
try this one
webSocket("/echo") {
send("Please enter your name")
try {
for (frame in incoming) {
when (frame) {
is Frame.Text -> {
val receivedText = frame.readText()
if (receivedText.equals("bye", ignoreCase = true)) {
close(CloseReason(CloseReason.Codes.NORMAL, "Client said BYE"))
break
} else {
send("Hi, $receivedText!")
while (isActive) {
send("1")
delay(2000)
}
}
}
is Frame.Ping -> send(Frame.Pong(frame.buffer))
else -> {}
}
}
} catch (e: Exception) {
println("WebSocket error: ${e.message}")
}
}
and in client side
deps.socketsClient.webSocket(
method = HttpMethod.Get,
host = host,
port = 8080,
path = "/echo"
) {
try {
for (frame in incoming) {
when (frame) {
is Frame.Text -> {
val number = frame.readText()
println("Received number: $number")
}
is Frame.Ping -> send(Frame.Pong(frame.buffer))
else -> {}
}
}
} catch (e: Exception) {
println("WebSocket error: ${e.message}")
}
}