一般客户端会每隔3秒向服务端发送一个空数据,即发送心跳包,如果网络没问题服务端会立刻回复一个心跳包,这时候就可以保持长链接了
//服务器响应心跳的时间,初始值用当前时间,防止重复重连
int callTime = DateTime.now().millisecondsSinceEpoch;
//在长链接收消息的处理里面
case WsMessageRoomCmd.CMD_BEAT_RESP:
//收到心跳,记录该心跳的当前时间
callTime = DateTime.now().millisecondsSinceEpoch;
PrintUtil.prints('房间麦序长链接 收到心跳$callTime');
if (_isOpened) {
_isBeatReply = true;
_retry_beat_index = 0;
}
break;
///发送心跳包
_sendBeat() async {
if (!_timerUtil.isActive()) {
//判断定时器是否再跑,这里只会进入一次
PrintUtil.prints('房间麦序长链接处理中台消息 定时器重新开始跑');
_timerUtil.setInterval(_MAX_BEAT_DELAYED * 1000);
_timerUtil.setOnTimerTickCallback((millisUntilFinished) {
//这里是定时器的回调,每三秒就回调一次,也就会执行这里面的方法
PrintUtil.prints('房间麦序长链接 发送心跳包');
//发送心跳包
_send(WsMessageRoomCmd.CMD_BEAT_REQ, encode(''));
//判断是否重连:客户端心跳一直发,距离上次心跳回应超过9秒就重连
if (getTimeInterval() == true) {
_handleRetry();
//刷新心跳应答,防止重复重连
callTime = DateTime.now().millisecondsSinceEpoch;
PrintUtil.prints('房间麦序长链接 开始重连');
}
_timerUtil.startTimer();
}
}
//判断是否重连
getTimeInterval() {
bool retry = false;
DateTime? callDate;
DateTime? nowDate;
callDate = DateTime.fromMillisecondsSinceEpoch(callTime);
nowDate = DateTime.fromMillisecondsSinceEpoch(
DateTime.now().millisecondsSinceEpoch);
var callDateTime = DateTime(callDate.year, callDate.month, callDate.day,
callDate.hour, callDate.minute, callDate.second);
var nowDateTime = DateTime(nowDate.year, nowDate.month, nowDate.day,
nowDate.hour, nowDate.minute, nowDate.second);
var difference = nowDateTime.difference(callDateTime);
PrintUtil.prints(
'房间麦序长链接 上一次心跳时间是$callTime 当前时间是${
DateTime.now().millisecondsSinceEpoch} 相差时间是${
difference.inSeconds}');
//心跳的间隔时间是3秒,距离上次心跳时间超过9秒就重连,30秒内可重连三次(相当于发了三次都还没收到心跳)
///问题是第9秒的时候开始重连了,
if (difference.inSeconds >= 9) {
retry = true;
}
return retry;
}