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。
- 确保安装了所需的依赖项。在这种情况下:
implementation("io.ktor:ktor-websockets:$ktor_version")
- 尝试像这样安装 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)
}
- 确保您的 WebSocket 配置正确:
install(WebSockets) {
pingPeriod = Duration.ofSeconds(15)
timeout = Duration.ofSeconds(15)
maxFrameSize = Long.MAX_VALUE
masking = false
}
- 在这种情况下
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()
}
}
无论服务器如何,我在启动后大约 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。
- 确保安装了所需的依赖项。在这种情况下:
implementation("io.ktor:ktor-websockets:$ktor_version")
- 尝试像这样安装 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)
}
- 确保您的 WebSocket 配置正确:
install(WebSockets) {
pingPeriod = Duration.ofSeconds(15)
timeout = Duration.ofSeconds(15)
maxFrameSize = Long.MAX_VALUE
masking = false
}
- 在这种情况下
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()
}
}