172 lines
5.5 KiB
C#
172 lines
5.5 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Text;
|
||
using Facebook.MiniJSON;
|
||
|
||
namespace BF
|
||
{
|
||
internal partial class TCPChannel
|
||
{
|
||
private const uint HeartBeat_Req_Group = 3763117270;
|
||
private const uint HeartBeat_Rsp_Group = 3763119103;
|
||
// private const byte HeartBeat_Req_Cmd = 2;
|
||
private const int HeartBeat_Rsp_OK = 0;
|
||
|
||
// 上一次发送心跳包的时间
|
||
private double lastSendHeartBeatTime = 0;
|
||
//已发送心跳包的数量;接收到任意返回心跳包就重置
|
||
private int sendHeartBeatCount = 0;
|
||
//不发心跳包的最长时间,超过这个时间,就开始重连(因为某些原因,造成网络线程暂停,此时需要这个逻辑)
|
||
private float maxHeartBeatMissTime = 0;
|
||
|
||
/// <summary>
|
||
/// 心跳包同步的服务器当前时间戳 ms
|
||
/// </summary>
|
||
private long serverTimestamp;
|
||
|
||
private void InitializeHeartBeat()
|
||
{
|
||
maxHeartBeatMissTime = ownerConnection.configuration.HeartBeatInterval *
|
||
ownerConnection.configuration.MaxHeartBeatMissCount;
|
||
|
||
ResetHeartBeatStatus();
|
||
}
|
||
|
||
private void HeartBeat()
|
||
{
|
||
if (!ownerConnection.configuration.EnableHeartBeat)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (actualStatus != NetConnectStatus.Connected)
|
||
{
|
||
return;
|
||
}
|
||
|
||
var nowSecond = NetTime.Now;
|
||
////距离上一次发送心跳包的时间
|
||
var waitHeartBeatInterval = nowSecond - lastSendHeartBeatTime;
|
||
if (waitHeartBeatInterval < ownerConnection.configuration.HeartBeatInterval)
|
||
{
|
||
return;
|
||
}
|
||
|
||
SendHeartBeat(nowSecond, waitHeartBeatInterval);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检测接收的消息是否是心跳包
|
||
/// </summary>
|
||
/// <param name="incomingMessage"></param>
|
||
/// <returns>true: 是心跳包;false: 其他消息</returns>
|
||
private bool FilterHeartBeatIncomingMessage(NetIncomingMessage incomingMessage)
|
||
{
|
||
if (incomingMessage.Group != HeartBeat_Rsp_Group)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
//receive heart beat success
|
||
ResetHeartBeatStatus();
|
||
|
||
this.serverTimestamp = 0;
|
||
|
||
//release heartbeat message
|
||
var heartbeatMessage = ownerConnection.CreateIncomingMessage(NetIncomingMessageType.HeartBeatMessage, null);
|
||
heartbeatMessage.HeartbeatSyncTimestamp = this.serverTimestamp;
|
||
ReleaseMessage(heartbeatMessage);
|
||
|
||
LogDebug("Heart beat success !!!");
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// receive any message, reset heart beat status
|
||
/// </summary>
|
||
private void ResetHeartBeatStatus()
|
||
{
|
||
sendHeartBeatCount = 0;
|
||
lastSendHeartBeatTime = NetTime.Now;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置上次心跳时间,立刻发送心跳
|
||
/// </summary>
|
||
private void ForceSendHeartBeatImmediately()
|
||
{
|
||
// lastSendHeartBeatTime = NetTime.Now - ownerConnection.configuration.HeartBeatInterval - 1;
|
||
lastSendHeartBeatTime = NetTime.Now;
|
||
}
|
||
|
||
private void SendHeartBeat(double nowSecond, double waitHeartBeatInterval)
|
||
{
|
||
if (actualStatus != NetConnectStatus.Connected)
|
||
{
|
||
return;
|
||
}
|
||
sendHeartBeatCount += 1;
|
||
//miss heart beat message to many, try reconnect.
|
||
if (sendHeartBeatCount > ownerConnection.configuration.MaxHeartBeatMissCount)
|
||
{
|
||
LogDebug("Miss heart beat max count, try reconnect.");
|
||
StartSmartReconnectCountdown();
|
||
ResetHeartBeatStatus();
|
||
return;
|
||
}
|
||
|
||
// 如果两次心跳包之间的时间间隔,超过了最大心跳次数的间隔,开始重连;
|
||
// 因为某些原因,造成网络线程暂停,此时需要这个逻辑;
|
||
if (waitHeartBeatInterval > maxHeartBeatMissTime)
|
||
{
|
||
LogDebug("Miss heart beat max time, try reconnect.");
|
||
StartSmartReconnectCountdown();
|
||
ResetHeartBeatStatus();
|
||
return;
|
||
}
|
||
|
||
var heartBeat = CreateHeartBeatOutgoingMessage();
|
||
SendInternal(heartBeat);
|
||
|
||
lastSendHeartBeatTime = nowSecond;
|
||
|
||
LogDebug("Begin send heart beat !!!");
|
||
}
|
||
|
||
private NetOutgoingMessage CreateHeartBeatOutgoingMessage()
|
||
{
|
||
var message = ownerConnection.CreateOutgoingMessage(NetOutgoingMessageType.UserData);
|
||
|
||
var heartBeatData = SerializeHeartBeatReq();
|
||
message.Encode(HeartBeat_Req_Group, 0, heartBeatData);
|
||
return message;
|
||
}
|
||
|
||
/// <summary>
|
||
/// @TODO Temp
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private byte[] SerializeHeartBeatReq()
|
||
{
|
||
byte[] data = {};
|
||
|
||
return data;
|
||
}
|
||
|
||
/// <summary>
|
||
/// @TODO Temp
|
||
/// </summary>
|
||
/// <param name="data"></param>
|
||
/// <param name="status"></param>
|
||
/// <returns></returns>
|
||
private bool DeserializeHeartBeatRsp(byte[] data, out long status, out long serverTimestamp)
|
||
{
|
||
serverTimestamp = 0;
|
||
status = 0;
|
||
|
||
return true;
|
||
}
|
||
}
|
||
}
|