using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Facebook.MiniJSON;
using ThinkingAnalytics;
namespace BF
{
internal partial class TCPChannel
{
private const uint Reconnect_Req_Group = 1068769299;
private const uint Reconnect_Rsp_Group = 1068771132;
private const byte Reconnect_Req_Cmd = 0;
private const int Reconnect_Rsp_OK = 0;
private enum SmartReconnectStatus
{
None,
Countdown,
TryReconnect,
}
private readonly object mSmartReconnectLock = new object();
///
/// 缓存一定数量已经发送的消息,为重连成功后,重发发送失败的数据包
///
private NetSafeQueue alreadySendMessagesQueue;
private Stack alreadySendExchangeStack;
///
/// 缓存重连期间,所有的外部发送消息;重连成功后,继续发送
///
private Queue waitingSendMessagesQueue;
///
/// 记录尝试重连的次数
///
private int tryReconnectCount = 0;
///
/// 用于区分是外部调用的重连逻辑,还是内部自动重连逻辑
///
private bool internalReconnectFlag = true;
#region Smart Reconnect
private float smartReconnectInterval = 5;
private double lastSmartStartTime = 0;
private SmartReconnectStatus smartStatus;
#endregion
private void InitializeReconnect()
{
int cacheSize = ownerConnection.configuration.AlreadySendMessageCacheCount;
alreadySendMessagesQueue = new NetSafeQueue(cacheSize);
alreadySendExchangeStack = new Stack();
waitingSendMessagesQueue = new Queue(cacheSize);
internalReconnectFlag = true;
}
///
/// 连接成功后,调用,重置重连信息
///
private void ResetTryReconnectCount()
{
tryReconnectCount = 0;
internalReconnectFlag = true;
}
///
/// 重连失败后,调用
///
private void TryReconnectFailed()
{
if (connectContext != NetConnectContext.Reconnect)
{
return;
}
}
///
/// 尝试重连,达到最大重连次数后,通知应用层
///
private bool TryReconnect()
{
if (!ownerConnection.configuration.EnableSilenceReconnect)
{
SetConnectContext(NetConnectContext.Invalid);
Disconnect();
LogError(NetErrorCode.PeerDisconnect, "TryReconnect, Disable silence reconnect, connect disconnect !!!");
return false;
}
// 必须在玩家连接成功后,重连才有意义;否则直接失败!!
if (visibleStatus != NetConnectStatus.Connected)
{
SetConnectContext(NetConnectContext.Invalid);
Disconnect();
LogError(NetErrorCode.PeerDisconnect, "TryReconnect, visibleStatus is connected, connect disconnect !!!");
return false;
}
if (connectContext == NetConnectContext.Reconnect)
{
var now = NetTime.Now;
if (tryReconnectCount >= ownerConnection.configuration.AutoReconnectCount)
{
SetConnectContext(NetConnectContext.Invalid);
Disconnect();
ResetTryReconnectCount();
LogError(NetErrorCode.PeerDisconnect, "Try reconnect failed, channel disconnect.");
return false;
}
}
// BFLog.Log($"Begin try reconnect : {tryReconnectCount}");
PrepareReconnect();
return true;
}
///
/// 重置状态,准备重连
///
private void PrepareReconnect()
{
//进入重连上下文
SetConnectContext(NetConnectContext.Reconnect);
//断开现有连接
Disconnect();
//缓存已经在sendMessageQueue中的消息,并清空sendMessageQueue;等待重连成功后,再继续发送
CacheAlreadyInSendMessageQueueMessage(sendMessageQueue);
//清除上一个TCP连接的发送接受消息队列,不要继续发送接受数据;等待重连成功后再次进行收发数据
ClearSendReceiveMessageQueue();
}
///
/// 重连,创建新连接
///
private void TryConnectNewConnect()
{
if (connectContext != NetConnectContext.Reconnect || actualStatus != NetConnectStatus.Disconnected)
{
return;
}
tryReconnectCount += 1;
//开始新的连接
ConnectInternalAsync();
}
///
/// 检测收到的消息是否是重连消息
///
///
/// true: 是重连消息;false: 其他消息
private bool FilterReconnectIncomingMessage(NetIncomingMessage incomingMessage)
{
if (connectContext != NetConnectContext.Reconnect)
{
return false;
}
if (incomingMessage.Group != Reconnect_Rsp_Group)
{
return false;
}
actualStatus = NetConnectStatus.Decoding2;
visibleStatus = NetConnectStatus.Decoding2;
incomingMessage.MessageType = NetIncomingMessageType.StatusChange;
incomingMessage.ConnectStatus = NetConnectStatus.Decoding2;
ReleaseMessage(incomingMessage);
decoding = false;
return true;
}
private bool FilterReconnectIncomingMessage2()
{
var isSuccess = DeserializeReconnectRsp(out var status, out var seqCs);
if (!isSuccess)
{
SetActualStatus(NetConnectStatus.Unauthorized);
return true;
}
if (status != Reconnect_Rsp_OK)
{
SetActualStatus(NetConnectStatus.Unauthorized);
return true;
}
//检查等待重新发送的消息
ResendMissingOutgoingMessage(seqCs);
// BFLog.Log($"End try reconnect : {tryReconnectCount}, success !!!");
ResetTryReconnectCount();
ResetSmartReconnect();
SetConnectContext(NetConnectContext.NewConnect);
SetActualStatus(NetConnectStatus.Connected);
ResetConnectTimeout();
ResetHeartBeatStatus();
// ResetOldSessionRc4Key();
ForceSendHeartBeatImmediately();
if(ownerConnection.UniqueIdentifier.CompareTo(BF.NetManager.MAIN_SOCKET_NAME) == 0)
{
BF.BFMain.Instance.NetMgr.decodeFinish = false;
}
else
{
BF.BFMain.Instance.NetMgr.decodeChatFinish = false;
}
return true;
}
///
/// 重连成功后,重新发送丢失的消息
///
/// 服务器接受到的最大 Seq
private void ResendMissingOutgoingMessage(long serverReceiveSeq)
{
BFLog.Log($"ResendMissingOutgoingMessage : serverReceiveSeq = {serverReceiveSeq}, sendMessageQueue = {sendMessageQueue.Count}");
List pendingResendMessages = new List();
alreadySendExchangeStack.Clear();
while (alreadySendMessagesQueue.Count > 0)
{
alreadySendMessagesQueue.TryDequeue(out var outgoingMessage);
if (outgoingMessage.Seq <= serverReceiveSeq)
{
ownerConnection.Recycle(outgoingMessage);
continue;
}
// seq为0的一定是重连后发送的第一条loginReq,除此以外的消息添加到发送队列
if (outgoingMessage.Seq != 0 && outgoingMessage.Group != HeartBeat_Req_Group)
{
pendingResendMessages.Add(outgoingMessage);
}
}
while (waitingSendMessagesQueue.Count > 0)
{
var outgoingMessage = waitingSendMessagesQueue.Dequeue();
//添加到发送队列
pendingResendMessages.Add(outgoingMessage);
// BFLog.Log($"ResendMissingOutgoingMessage waitingSendMessagesQueue : {outgoingMessage.Group}, {outgoingMessage.Cmd}, {outgoingMessage.Seq}");
}
List> msgsPack = new List>();
foreach (NetOutgoingMessage message in pendingResendMessages)
{
// byte[] data = messageService.SerializeRaw(message);
// msgsPack.Add(data.ToList());
for (int index = 0; index < message.Data.Length; ++ index)
{
if (message.Data[index] == 0)
{
message.PackDataLength = index;
break;
}
}
byte[] data = new byte[message.PackDataLength];
Array.Copy(message.Data, data, message.PackDataLength);
BFLog.Log($"ResendMissingOutgoingMessage SerializeRaw : {message.Group}, {message.Cmd}, {message.Seq}");
var outgoingMsg = ownerConnection.CreateOutgoingMessage(NetOutgoingMessageType.UserData);
outgoingMsg.Encode(message.Group, message.Cmd, data);
outgoingMsg.Seq = message.Seq;
EnqueueRawSendMessage(outgoingMsg);
// BFLog.Log("==================================== message.PackDataLength = " + message.PackDataLength.ToString());
// int min = Math.Min(message.PackDataLength, 10);
// for (int index = 0; index < min; ++ index)
// {
// BFLog.Log("message.Data[{0}] = {1}", index, message.Data[index]);
// }
// BFLog.Log("==================================== message.Data.Length = " + message.Data.Length.ToString());
}
}
///
/// 发送重连请求
///
private void SendReconnectMessage()
{
if (connectContext != NetConnectContext.Reconnect)
{
return;
}
// var reconnectReq = SerializeReconnectReq();
var outgoingMsg = ownerConnection.CreateOutgoingMessage(NetOutgoingMessageType.UserData);
var bytes = BF.BFMain.Instance.NetMgr.GetLoginReqData();
outgoingMsg.Encode(Reconnect_Req_Group, Reconnect_Req_Cmd, bytes);
// BFLog.Log("=============== SendReconnectMessage");
EnqueueRawSendMessage(outgoingMsg);
}
///
/// @TODO Temp
///
///
private bool DeserializeReconnectRsp(out long status, out long seqCs)
{
// BFLog.Log("==================================== DeserializeReconnectRsp");
string pbData;
if(ownerConnection.UniqueIdentifier.CompareTo(BF.NetManager.MAIN_SOCKET_NAME) == 0)
{
pbData = BF.BFMain.Instance.NetMgr.GetDecodePbStr();
}
else
{
pbData = BF.BFMain.Instance.NetMgr.GetDecodeChatPbStr();
}
Dictionary dict = Json.Deserialize(pbData) as Dictionary;
// BFLog.Log("==================================== DeserializeReconnectRsp pbData = " + pbData);
// BFLog.Log("==================================== DeserializeReconnectRsp status = " + (long)dict["status"]);
// BFLog.Log("==================================== DeserializeReconnectRsp send_id = " + (long)dict["send_id"]);
status = (long)dict["status"];
seqCs = (long)dict["send_id"];
return status == 0;
}
#region Reconnect message sync
private bool FilterMissingDataSyncIncomingMessage(NetIncomingMessage incomingMessage)
{
if (incomingMessage.Group != 0 || incomingMessage.CMD != 3)
{
return false;
}
var isSuccess = DeserializeMissingMessageSync(incomingMessage.Data, out var missingReceiveData);
if (!isSuccess)
{
//重连消息解析失败,判定为重连不成功,不做任何其他处理,继续等待到连接超时;
return true;
}
//接收到补发消息,解析协议后,直接release
foreach (var receiveData in missingReceiveData)
{
var incomingMsg = ownerConnection.CreateIncomingMessage(NetIncomingMessageType.Data, receiveData);
messageService.DeserializeRaw(incomingMsg, receiveSeq);
ReleaseMessage(incomingMsg);
// BFLog.Log($"FilterMissingDataSyncIncomingMessage: {incomingMsg.Group}, {incomingMsg.CMD}, {incomingMsg.Seq}");
}
//reconnect success
ResetTryReconnectCount();
ResetSmartReconnect();
SetConnectContext(NetConnectContext.NewConnect);
SetActualStatus(NetConnectStatus.Connected);
ResetConnectTimeout();
ResetHeartBeatStatus();
ResetOldSessionRc4Key();
ForceSendHeartBeatImmediately();
return true;
}
private bool DeserializeMissingMessageSync(byte[] data, out List missingReceiveData)
{
missingReceiveData = new List();
string syncString = Encoding.UTF8.GetString(data);
Dictionary syncObj = Json.Deserialize(syncString) as Dictionary;
if (syncObj == null)
{
return false;
}
if (syncObj.Count <= 0)
{
return true;
}
List