websocket bug

  • Creator 版本:cocos creator3.5.1;cocos creator3.5.2;cocos creator3.6.1

  • 目标平台:Android

  • 重现方式:搭建一个websocket服务器(我用的nodejs),在把运行的apk切到后台情况下,服务端主动关闭连接。这个时候会输出一个”Closing :1005“的log,切回到运行的apk发现客户端创建的websocket实例readystate为OPEN,并不能立刻知道websocket的断开状态,需要等一段时间(我测试发现大概在15-30s)。我使用cocos creator2.4.4也测试过,没有发现这个问题,能够立刻准确地知道websocket的断开状态。

  • 首个报错:
    2.4.4截图:


    3.6.1截图:

    3.5.1;3.5.2错误与3.6.1一致

  • 之前哪个版本是正常的:cocos creator2.4.4没有这个问题

  • 手机型号:小米9,华为meta40pro

  • 手机浏览器:原生

  • 编辑器操作系统:Android

  • 重现概率:100%

我是在接入原生支付sdk时发现的bug,每次只要玩家支付时间太长就会导致充值不能马上到账,需要玩家在下次进入游戏时进行补单,因为我没法在resume时立刻知道连接的状态。

希望这个bug能引起关注,并进行解决!

拜谢!

2赞

mark!

mark2

调起支付或者播放激励视频广告是用了新的activity,原来游戏层的activity所有任务就会被暂停。我目前的处理方式是延长心跳时间+返回游戏界面直接先close ws再重连,连上之后再发消息

嗯嗯,我也想过这样去处理,但还是感觉不是很好。这样前后台切换都会触发关闭和重连了。

在因为这个问题卡住两三天期间,写了demo去验证每个版本的情况,只有2.4.4版本是没有问题的。我去对比了2.4.4和3.5.1,3.5.2,3.6.1websocket的实现,发现2.4.4使用的是WebSocket-libwebsockets.cpp而3.5.x,3.6.x使用的是WebSocket-okhttp.cpp,刚开始没有怀疑过这个。最后抱着试试的心理替换成了2.4.4版本使用的WebSocket-libwebsockets.cpp,我使用的3.5.1版本没有这个问题了。。。猜测3.5.x,3.6.x也可以这样去解决这个问题(我没验证过)。
怎么替换呢?
1.找到3.5.1安装路径,打开如下路径的CMakeLists.txt
D:\CocosDashboard_1.0.12\resources.editors\Creator\3.5.1\resources\resources\3d\engine\native\CMakeLists.txt(这是我的安装路径下的)
2.778行 NO_WERROR cocos/network/WebSocket-okhttp.cpp 换成 NO_WERROR cocos/network/WebSocket-libwebsockets.cpp
ok!重新打包试试看~

听起来好像是okhttp相关的问题, 是否方便发个可复现的demo我们这边看看?

怎么给你提供demo呢?我发现没有上传zip的权限。

我私信你邮箱

OK,已经发你邮箱了

收到. 后续有进展会第一时间告知

我个人觉得这个不算bug,因为会有很多情况,导致链接不通畅,不仅限于一头关闭,所以心跳包是必要的。

切到后台了,你的程序都停住了 不能再循环TICK了都 你的心跳包 怎么发出去呢? 不能接受数据 也不能发送数据了 这个机制没法起作用了都

是的,心跳机制我们有做。客户端切到后台时间太久,服务端认为客户端退出或者其它原因断开了,就会主动关闭这个连接。

https://github.com/cocos/cocos-engine/pull/12783 看看这个修复能不能解决上述的问题?

1赞

已经使用 直接替换掉WebSocket-okhttp.cpp 的方法去做的了。改天有时间我再来试试这个pr有没有解决这个问题,不过看着应该是可以,之前测试也是每次都是进入到onClosing,然后过15~30s才真正关闭了连接。

我遇到一个问题 不知道贴主有没有遇到 就是客户端一断wifi websocket马上触发onclose 但在web端是要过10秒左右 这个时间应该是跟链接设置有关 但是对于移动设备一断就马上触发 这个遇到过么 是怎么处理 心跳包一直也有发的 也确认没有主动closeSocket

我也遇到这个bug了 真的感谢你

是有这个问题,你这边解决了没 还是降版本回到3.4.2

通过setTimeout缓一下就可以了,查过一些资料是由于当帧任务被系统os线程回收了,具体的原因有点忘了,但是通过setTimeout后就可以,宏任务默认是至少在一个渲染帧后触发,所以就避开了这个坑