websocket 的 问题
目前服务端使用的是 swoole
的 websocket
,用redis
绑定用户与资源符fd
。
用户可能多端登录,于是当用户登录 socket
后,用的 redis
类型是 set
类型,即 'user:5' => [fd1,fd2..]
,当服务端 onClose
时把当前 fd
从[fd1,fd2..]
中删除。
但运行中发现,可能有的用户下线,没有走 onClose
,具体什么原因我不清楚,可能是应用被杀死,或者断网了。 自己组里的fd
没有及时清除,导致[fd1,fd2..]
中有无效的fd
,或者根本就是别人的fd
了,如果不加判断,会造成消息发送给了其他人。
不论在哪个步骤去检查整理[fd1,fd2..]
,筛选出属于自己的fd
,都不能准确的判断当前用户是否在线,登录了多少个端。
没有好的思路,求助。
谢谢大家的回复。swoole服务器开启心跳检测对于我这个项目不太适合,因为app应用黑屏一段时间以后,客户端js的定时器ping会停止,但不代表这个链接已经关闭了。
我在服务端加了一个定时器,检查所有fd是不是websocket链接,发现非正常close的fd,$server->isEstablished($fd) 仍然返回true。
正在参考回帖中的超时未回复踢下线,没有回复就代表客户端收不到消息也不会提醒通知了,在不在线也就没意义了,稍后再回复。
最后采用服务器定时ping客户端,如果没有回复就剔除该 fd ,断网、主动退出、redis数据被清除的情况,盯了几个小时,数据正常,再观察看看。
大家说的都对,是我理解错了,服务器端开启心跳检测即可。
'open_tcp_keepalive' => 1,//Keep-Alive 的机制可以检测死连接
'tcp_keepidle' => 10, //30s没有数据传输就进行检测
'tcp_keepinterval' => 1, //1s探测一次
'tcp_keepcount' => 5, //探测的次数,超过5次后还没回包close此连接
就解决了,客户端甚至无需ping,客户端ping的目的是万一服务器清理了redis,或者fd和用户双向绑定不一致的异常情况。
到此解决,谢谢大家!
给每个链接做心跳检测,超时未回复踢下线