websocket 的 问题

目前服务端使用的是 swoolewebsocket,用redis绑定用户与资源符fd

用户可能多端登录,于是当用户登录 socket 后,用的 redis 类型是 set 类型,即 'user:5' => [fd1,fd2..],当服务端 onClose 时把当前 fd[fd1,fd2..] 中删除。

但运行中发现,可能有的用户下线,没有走 onClose,具体什么原因我不清楚,可能是应用被杀死,或者断网了。 自己组里的fd没有及时清除,导致[fd1,fd2..]中有无效的fd,或者根本就是别人的fd了,如果不加判断,会造成消息发送给了其他人。

不论在哪个步骤去检查整理[fd1,fd2..],筛选出属于自己的fd,都不能准确的判断当前用户是否在线,登录了多少个端。

没有好的思路,求助。

welcome come back
附言 1  ·  3年前

谢谢大家的回复。swoole服务器开启心跳检测对于我这个项目不太适合,因为app应用黑屏一段时间以后,客户端js的定时器ping会停止,但不代表这个链接已经关闭了。

我在服务端加了一个定时器,检查所有fd是不是websocket链接,发现非正常close的fd,$server->isEstablished($fd) 仍然返回true。

正在参考回帖中的超时未回复踢下线,没有回复就代表客户端收不到消息也不会提醒通知了,在不在线也就没意义了,稍后再回复。

附言 2  ·  3年前

最后采用服务器定时ping客户端,如果没有回复就剔除该 fd ,断网、主动退出、redis数据被清除的情况,盯了几个小时,数据正常,再观察看看。

附言 3  ·  3年前

大家说的都对,是我理解错了,服务器端开启心跳检测即可。
'open_tcp_keepalive' => 1,//Keep-Alive 的机制可以检测死连接
'tcp_keepidle' => 10, //30s没有数据传输就进行检测
'tcp_keepinterval' => 1, //1s探测一次
'tcp_keepcount' => 5, //探测的次数,超过5次后还没回包close此连接

就解决了,客户端甚至无需ping,客户端ping的目的是万一服务器清理了redis,或者fd和用户双向绑定不一致的异常情况。

到此解决,谢谢大家!

《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
最佳答案

给每个链接做心跳检测,超时未回复踢下线

3年前 评论
讨论数量: 7

给每个链接做心跳检测,超时未回复踢下线

3年前 评论

使用心跳检测机制即可。

3年前 评论

心跳检测

3年前 评论
  1. fd 需要做成唯一的就像session一样
  2. 心跳检测是必须的,但是需要依靠心跳检测出来的不在线的情况比较少(类似于网络抖动导致的掉线)
  3. 你应该没有监听用户下线事件(或者这一块没做好),ws是双向长连接正常情况下服务器都是能知道的
3年前 评论
php_yt (楼主) 3年前
php_yt (楼主) 3年前

我用workman 来搭建websocket,实现了在线客服和聊天室功能。(https://element.wmhello.cn)

8个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!