如何保持 Kotlin Ktor websocket 处于打开状态

Posted

技术标签:

【中文标题】如何保持 Kotlin Ktor websocket 处于打开状态【英文标题】:How to keep a Kotlin Ktor websocket open 【发布时间】:2021-03-26 14:34:51 【问题描述】:

创建了一个 ktor 服务器 websocket 端点。

尽管处于while (true) 循环中,但它拒绝保持打开状态:

服务器

routing 
    webSocket("/data") 
        while (true) 
            send(Frame.Text("Howdy"))
            delay(5000)
        
    

客户端(浏览器)

const ws = new WebSocket("ws://www.example.com:1234/data")

客户端(浏览器)连接并接收消息,但随后套接字关闭。

为什么这个 ws 一直关闭?我从未发出过“关闭”命令。如何保持打开状态,以便发送新的排队消息?

参考: https://ktor.io/docs/servers-features-websockets.html#usage

【问题讨论】:

【参考方案1】:

我的猜测是您没有在客户端 websocket 上注册侦听器,一旦建立连接,由于没有侦听器而断开连接。或者可能正在接收消息,但您需要通过注册显式侦听器将它们输出到某个地方。

为了测试您的代码,我尝试了this Ktor WebSocket Chat tutorial。我首先克隆 the sample repository 并使用 IntelliJ IDEA CE 打开服务器文件夹。然后,我打开了Application.kt 文件并用以下几行替换了 Application 模块,与您的示例非常相似:

@Suppress("unused")
fun Application.module() 
    install(WebSockets)
    routing 
        webSocket("/data") 
            send("You are connected!")
            while (true) 
                send(Frame.Text("Howdy"))
                delay(1_000)
            
        
    

那个教程在第 3 章告诉你打开an html echo websocket client,但这对我不起作用,它总是说ERROR: undefined(我猜是因为偏执的网络权限?)。但是,在该网页的底部,有一个连接到 websocket 的示例 HTML 代码,它工作正常!我复制了示例并稍作修改,将以下行放入test.html 文件中:

  <!DOCTYPE html>
  <meta charset="utf-8" />
  <title>WebSocket Test</title>
  <script language="javascript" type="text/javascript">

  var wsUri = "ws://localhost:8080/data";
  var output;

  function init()
  
    output = document.getElementById("output");
    testWebSocket();
    window.setTimeout(delayedTest, 5000);
  

  function delayedTest()
  
    websocket.close();
    //alert("delayed");
  

  function testWebSocket()
  
    websocket = new WebSocket(wsUri);
    websocket.onopen = function(evt)  onOpen(evt) ;
    websocket.onclose = function(evt)  onClose(evt) ;
    websocket.onmessage = function(evt)  onMessage(evt) ;
    websocket.onerror = function(evt)  onError(evt) ;
  

  function onOpen(evt)
  
    writeToScreen("CONNECTED");
    doSend("WebSocket rocks");
  

  function onClose(evt)
  
    writeToScreen("DISCONNECTED");
  

  function onMessage(evt)
  
    writeToScreen('<span style="color: blue;">RESPONSE: ' + evt.data+'</span>');
    //websocket.close();
  

  function onError(evt)
  
    writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
  

  function doSend(message)
  
    writeToScreen("SENT: " + message);
    websocket.send(message);
  

  function writeToScreen(message)
  
    var pre = document.createElement("p");
    pre.style.wordWrap = "break-word";
    pre.innerHTML = message;
    output.appendChild(pre);
  

  window.addEventListener("load", init, false);

  </script>

  <h2>WebSocket Test</h2>

  <div id="output"></div>

一旦您运行了 ktor websocket 服务器,打开该 HTML 文件就会向我显示以下行,这表明连接已建立,因为服务器会定期发送 Howdy 消息,直到 HTML javascript 超时触发并关闭套接字:

CONNECTED

SENT: WebSocket rocks

RESPONSE: Howdy

RESPONSE: Howdy

RESPONSE: Howdy

RESPONSE: Howdy

RESPONSE: Howdy

DISCONNECTED

编辑更新:为了测试套接字是否没有接收消息,或者它正在接收消息但没有打印它们,我在我的test.html 文件中进一步修改了testWebSocket() 以包含以下行:

  function testWebSocket()
  
    websocket = new WebSocket(wsUri);
    //websocket.onopen = function(evt)  onOpen(evt) ;
    //websocket.onclose = function(evt)  onClose(evt) ;
    //websocket.onmessage = function(evt)  onMessage(evt) ;
    //websocket.onerror = function(evt)  onError(evt) ;
  

这些行相当于您的原始代码,我没有得到任何答案。但是,如果我打开 Safari 网络调试面板并单击 data 流,我可以看到在超时显式关闭套接字之前 HTML 页面仍然接收Howdy 事件。

【讨论】:

以上是关于如何保持 Kotlin Ktor websocket 处于打开状态的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Kotlin 的 Ktor 中提取访问权限验证

如何使用内容协商将 json 转换为 ktor 中的 kotlin 对象?

Kotlin Multiplatform Mobile:Ktor - 如何在 Kotlin Native(iOS)中取消活动协程(网络请求、后台工作)?

如何在 Ktor (Kotlin) 中管道的各个部分之间传递数据

如何使用 ktor kotlin 通过 POST 发送 JSON 字符串?

如何使用带有 ktor 框架的 graphql-kotlin 进行字段级解析器