Ktor WebSocket 客户端:连接在启动后约 1 分钟内拒绝,原因不明

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

无论服务器如何,我在启动后大约 1 分钟收到 ClosedReceiveChannelException,原因不明。我究竟做错了什么?
代码:

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()
  }
}

错误:

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.

我建议看看 Ktor 的 Server WebSocket documentation

  1. 确保安装了所需的依赖项。在这种情况下:
implementation("io.ktor:ktor-websockets:$ktor_version")
  1. 尝试像这样安装 WebSocket:
import io.ktor.features.*
// ...
fun Application.module() {
    install(WebSockets)
    // ...
}

import io.ktor.features.*
// ...
fun main() {
    embeddedServer(Netty, port = 8080) {
        install(WebSockets)
        // ...
    }.start(wait = true)
}
  1. 确保您的 WebSocket 配置正确:
install(WebSockets) {
    pingPeriod = Duration.ofSeconds(15)
    timeout = Duration.ofSeconds(15)
    maxFrameSize = Long.MAX_VALUE
    masking = false
}
  1. 在这种情况下 while(true) 调用是没有必要的。您可以通过执行以下操作来完成同样的事情:
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!"))
                    }
                }
            }
        }
    }
}

已解决。在客户端配置中设置 pingInterval 解决了这个问题。 最终代码:

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()
  }
}