为什么需要心跳检测?
有些极端情况如客户端掉电、网络关闭、拔网线、路由故障等,这些极端情况都属于连接断开的情况,
然而这些情况如果没有应用层的心跳检测,服务端是无法快速感知的。
而服务端定时向客户端发送心跳数据可以解决这个问题。
心跳检测的原理是什么?
判断对方(设备,进程或其它网元)是否正常动行,一般采用定时发送简单的通讯包,
如果在指定时间段内未收到对方响应,则判断对方已经当掉。用于检测TCP的异常断开。
服务端向客户端发送心跳检测,客户端接收到心跳数据后,可以忽略不做任何处理,也可以回应心跳检测,
这就分为两种情况:
当服务端不要求客户端必须回应心跳检测时,假如客户端遇到掉电等极端情况,
这时服务端向客户端发送的心跳数据在TCP
层面就会发送超时,
遇到这种超时情况TCP
会重试多次(次数及间隔依赖操作系统的配置),多次无果后会断开连接。
这种极端情况从连接断开到服务端检测到可能要持续至少10分钟。当服务端要求必须回应检测时,如果服务端在规定的时间内没有收到客户端的任何数据,
则立刻判定客户端已经断开,服务端就立即断开连接。
心跳检测可以是服务端主动,也可以是客户端主动,一般客户端来发会好点,对服务端压力没那么大
“心跳”分为两种,第一种是客户端发起的心跳,第二种是服务端发起的心跳。
客户端发起的心跳
客户端每隔一段时间发送策略消息给Socket
服务器,Socket
服务器原路返回策略消息,
如果客户端在设定时间段内没有收到Socket
服务器的返回消息,经重试机制后,判定Socket
服务器已Down
,关闭连接。
服务端发起的心跳
服务端实时记录每条Socket
的IO
操作时间,每隔一段时间获取所有Socket
列表的快照,扫描每条Socket
,
如果该Socket
的IO
操作时间距当前时间已超出设定值,则判定客户端Down
,关闭连接。
基于Workerman
的PHP
心跳
1 |
|
Swoole
做心跳检测
事实上,Swoole
已经内置了心跳检测功能,能自动close
掉长时间没有数据来往的连接。
而开启心跳检测功能,只需要设置heartbeat_check_interval
和heartbeat_idle_time
即可。如下:
1 | $this->serv->set( |
其中heartbeat_idle_time
的默认值是heartbeat_check_interval
的两倍。
在设置这两个选项后,swoole
会在内部启动一个线程,每隔heartbeat_check_interval
秒后遍历一次全部连接,检查最近一次发送数据的时间和当前时间的差,
如果这个差值大于heartbeat_idle_time
,则会强制关闭这个连接,并通过回调onClose
通知Server
进程
结合之前的Timer
功能,如果我们想维持连接,就设置一个略小于如果这个差值大于heartbeat_idle_time
的定时器,
在定时器内向所有连接发送一个心跳包。如果收到心跳回应,则判断连接正常,如果没有收到,则关闭这个连接或者再次尝试发送。
互联网推送原理: 长连接+心跳机制