You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

KMM项目iOS端WebSocket重复连接:如何实现非阻塞单次连接?

解决KMM iOS端WebSocket双重连接问题

我在开发Kotlin Multiplatform Mobile(KMM)项目,用WebSocket实现聊天功能,Android端运行正常,但iOS端每次连接服务器会创建两个用户,导致接收每条消息两次,服务器也会将其识别为两个不同的用户ID。测试发现直接用runBlocking能实现单次连接,但会阻塞主线程,无法正常使用应用,怀疑iOS端Dispatchers.Default行为与Android不同,需要实现非阻塞的单次连接方案。

问题根源

你的客户端代码在CoroutineScope(Dispatchers.Default).launch内部嵌套了runBlocking,这在Kotlin/Native的iOS协程模型中会触发意外的重复执行,导致两次WebSocket连接请求。同时runBlocking会阻塞线程,违背了非阻塞的设计初衷。

解决方案

移除嵌套的runBlocking,改用适配网络场景的协程调度器,同时做好生命周期管理:

修正后的客户端代码:

private fun clientMain() {
    // 建议根据平台绑定合适的协程作用域,比如iOS用MainScope,Android用viewModelScope
    val scope = CoroutineScope(Dispatchers.IO)
    scope.launch {
        delay(2000)
        try {
            client.webSocket("ws://$localIp:13276/ws") {
                send(Frame.Text("Test Message"))
                for (frame in incoming) {
                    val message = (frame as Frame.Text).readText()
                    println(message)
                    // 若需更新UI,切换到Main调度器(iOS UI操作必须在主线程执行)
                    withContext(Dispatchers.Main) {
                        // 此处添加UI更新逻辑
                    }
                }
            }
        } catch (e: Exception) {
            println("WebSocket连接异常: ${e.localizedMessage}")
        } finally {
            client.close()
            println("连接已关闭")
        }
    }
}

关键说明

  • 移除runBlocking:webSocket本身是挂起函数,可直接在协程内调用,无需阻塞线程。
  • 选择适配的调度器:网络IO操作推荐使用Dispatchers.IO,Dispatchers.Default更适合CPU密集型任务。
  • UI线程切换:iOS的UI操作必须在主线程执行,收到消息后若要更新UI,需通过withContext(Dispatchers.Main)切换调度器。
  • 生命周期管理:避免使用全局协程作用域,建议绑定到页面/组件的生命周期(比如iOS中在视图控制器初始化时创建MainScope,销毁时调用cancel())。

内容的提问来源于stack exchange,提问作者Adrian S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 03:35:32