Home > Mobile >  Ktor WebSocket Client: Connection refuses about in 1 min after startup for unknown reason
Ktor WebSocket Client: Connection refuses about in 1 min after startup for unknown reason

Time:11-23

Regardless of the server, I get ClosedReceiveChannelException about 1 minute after startup for unknown reason. What am i doing wrong?
Code:

val client = HttpClient(CIO) {
  install(WebSockets)
}
// Coroutine Scope
client.webSocket(host = "ws.ifelse.io") {
  try {
    while (true) {
      val rawPayload = incoming.receive() as? Frame.Text ?: continue
      println(rawPayload.readText())
    }
  } catch (e: Exception) {
    log.error("Caused unexpected exception while receiving payload:\n${e.stackTraceToString()}")
    client.close()
  }
}

Error:

kotlinx.coroutines.channels.ClosedReceiveChannelException: Channel was closed
    at kotlinx.coroutines.channels.Closed.getReceiveException(AbstractChannel.kt:1141)
    at kotlinx.coroutines.channels.AbstractChannel$ReceiveElement.resumeReceiveClosed(AbstractChannel.kt:938)
    at A really long call stack that prevents me from posting the question, but if necessary I can post the whole error.

CodePudding user response:

I would recommend having a look at Ktor's Server WebSocket documentation.

  1. Make sure you have the required dependencies installed. In this case:
implementation("io.ktor:ktor-websockets:$ktor_version")
  1. Try installing the WebSocket like this:
import io.ktor.features.*
// ...
fun Application.module() {
    install(WebSockets)
    // ...
}

or

import io.ktor.features.*
// ...
fun main() {
    embeddedServer(Netty, port = 8080) {
        install(WebSockets)
        // ...
    }.start(wait = true)
}
  1. Make sure your WebSocket configuration is correct:
install(WebSockets) {
    pingPeriod = Duration.ofSeconds(15)
    timeout = Duration.ofSeconds(15)
    maxFrameSize = Long.MAX_VALUE
    masking = false
}
  1. A while(true) call in this case is not necessary. You can accomplish the same thing by doing something like this:
routing {
        webSocket("/echo") {
            send("Please enter your name")
            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"))
                        else send(Frame.Text("Hi, $receivedText!"))
                    }
                }
            }
        }
    }
}

CodePudding user response:

Solved. Setting pingInterval in the client config solved the problem. Final code:

val client = HttpClient(CIO) {
  install(WebSockets) {
    pingInterval = 500
  }
}
// Coroutine Scope
client.webSocket("ws.ifelse.io") {
  try {
    for (frame in incoming) {
      frame as? Frame.Text ?: continue
      println(frame.readText())
    }
  } catch (e: Exception) {
    log.error("Caused unexpected exception while receiving payload:\n${e.stackTraceToString()}")
    client.close()
  }
}
  • Related